Programmatically apply new formatting to code

Run this:

for i in  **/*.cc **/*.c **/*.h **/*.hh; do
  clang-format < $i >| $i.new && mv $i.new $i
done
This commit is contained in:
Jay Berkenbilt 2022-04-02 17:14:10 -04:00
parent f20fa61eb4
commit 12f1eb15ca
244 changed files with 15234 additions and 18975 deletions

View File

@ -1,11 +1,11 @@
#include <qpdf/QPDF.hh> #include <qpdf/QPDF.hh>
#include <qpdf/QUtil.hh>
#include <qpdf/QPDFWriter.hh>
#include <qpdf/QPDFEmbeddedFileDocumentHelper.hh> #include <qpdf/QPDFEmbeddedFileDocumentHelper.hh>
#include <qpdf/QPDFFileSpecObjectHelper.hh> #include <qpdf/QPDFFileSpecObjectHelper.hh>
#include <qpdf/QPDFWriter.hh>
#include <qpdf/QUtil.hh>
#include <iostream>
#include <cstring> #include <cstring>
#include <iostream>
// //
// This example attaches a file to an input file, adds a page to the // This example attaches a file to an input file, adds a page to the
@ -17,9 +17,11 @@
static char const* whoami = 0; static char const* whoami = 0;
static void usage(std::string const& msg) static void
usage(std::string const& msg)
{ {
std::cerr << msg << std::endl << std::endl std::cerr << msg << std::endl
<< std::endl
<< "Usage: " << whoami << " options" << std::endl << "Usage: " << whoami << " options" << std::endl
<< "Options:" << std::endl << "Options:" << std::endl
<< " --infile infile.pdf" << std::endl << " --infile infile.pdf" << std::endl
@ -30,33 +32,36 @@ static void usage(std::string const& msg)
exit(2); exit(2);
} }
static void process(char const* infilename, char const* password, static void
char const* attachment, char const* mimetype, process(
char const* outfilename) char const* infilename,
char const* password,
char const* attachment,
char const* mimetype,
char const* outfilename)
{ {
QPDF q; QPDF q;
q.processFile(infilename, password); q.processFile(infilename, password);
// Create an indirect object for the built-in Helvetica font. This // Create an indirect object for the built-in Helvetica font. This
// uses the qpdf literal syntax introduced in qpdf 10.6. // uses the qpdf literal syntax introduced in qpdf 10.6.
auto f1 = q.makeIndirectObject( auto f1 = q.makeIndirectObject("<<"
"<<" " /Type /Font"
" /Type /Font" " /Subtype /Type1"
" /Subtype /Type1" " /Name /F1"
" /Name /F1" " /BaseFont /Helvetica"
" /BaseFont /Helvetica" " /Encoding /WinAnsiEncoding"
" /Encoding /WinAnsiEncoding" ">>"_qpdf);
">>"_qpdf);
// Create a resources dictionary with fonts. This uses the new // Create a resources dictionary with fonts. This uses the new
// parse introduced in qpdf 10.2 that takes a QPDF* and allows // parse introduced in qpdf 10.2 that takes a QPDF* and allows
// indirect object references. // indirect object references.
auto resources = q.makeIndirectObject( auto resources = q.makeIndirectObject(QPDFObjectHandle::parse(
QPDFObjectHandle::parse( &q,
&q, "<<"
"<<" " /Font <<"
" /Font <<" " /F1 " +
" /F1 " + f1.unparse() + f1.unparse() +
" >>" " >>"
">>")); ">>"));
@ -66,8 +71,7 @@ static void process(char const* infilename, char const* password,
<< std::endl; << std::endl;
auto fs = QPDFFileSpecObjectHelper::createFileSpec(q, key, attachment); auto fs = QPDFFileSpecObjectHelper::createFileSpec(q, key, attachment);
if (mimetype) if (mimetype) {
{
// Get an embedded file stream and set mimetype // Get an embedded file stream and set mimetype
auto ef = QPDFEFStreamObjectHelper(fs.getEmbeddedFileStream()); auto ef = QPDFEFStreamObjectHelper(fs.getEmbeddedFileStream());
ef.setSubtype(mimetype); ef.setSubtype(mimetype);
@ -102,17 +106,16 @@ static void process(char const* infilename, char const* password,
apdict.replaceKey("/Type", "/XObject"_qpdf); apdict.replaceKey("/Type", "/XObject"_qpdf);
apdict.replaceKey("/Subtype", "/Form"_qpdf); apdict.replaceKey("/Subtype", "/Form"_qpdf);
apdict.replaceKey("/BBox", "[ 0 0 20 20 ]"_qpdf); apdict.replaceKey("/BBox", "[ 0 0 20 20 ]"_qpdf);
auto annot = q.makeIndirectObject( auto annot = q.makeIndirectObject(QPDFObjectHandle::parse(
QPDFObjectHandle::parse( &q,
&q, "<<"
"<<" " /AP <<"
" /AP <<" " /N " +
" /N " + ap.unparse() + ap.unparse() +
" >>" " >>"
" /Contents " " /Contents " +
+ QPDFObjectHandle::newUnicodeString(attachment).unparse() + QPDFObjectHandle::newUnicodeString(attachment).unparse() +
" /FS " + fs.getObjectHandle().unparse() + " /FS " + fs.getObjectHandle().unparse() + " /NM " +
" /NM " +
QPDFObjectHandle::newUnicodeString(attachment).unparse() + QPDFObjectHandle::newUnicodeString(attachment).unparse() +
" /Rect [ 72 700 92 720 ]" " /Rect [ 72 700 92 720 ]"
" /Subtype /FileAttachment" " /Subtype /FileAttachment"
@ -134,12 +137,16 @@ static void process(char const* infilename, char const* password,
auto page = QPDFObjectHandle::parse( auto page = QPDFObjectHandle::parse(
&q, &q,
"<<" "<<"
" /Annots [ " + annot.unparse() + " ]" " /Annots [ " +
" /Contents " + contents.unparse() + annot.unparse() +
" /MediaBox [0 0 612 792]" " ]"
" /Resources " + resources.unparse() + " /Contents " +
" /Type /Page" contents.unparse() +
">>"); " /MediaBox [0 0 612 792]"
" /Resources " +
resources.unparse() +
" /Type /Page"
">>");
// Add the page. // Add the page.
q.addPage(page, true); q.addPage(page, true);
@ -151,7 +158,8 @@ static void process(char const* infilename, char const* password,
w.write(); w.write();
} }
int main(int argc, char* argv[]) int
main(int argc, char* argv[])
{ {
whoami = QUtil::getWhoami(argv[0]); whoami = QUtil::getWhoami(argv[0]);
@ -162,64 +170,46 @@ int main(int argc, char* argv[])
char const* mimetype = 0; char const* mimetype = 0;
auto check_arg = [](char const* arg, std::string const& msg) { auto check_arg = [](char const* arg, std::string const& msg) {
if (arg == nullptr) if (arg == nullptr) {
{
usage(msg); usage(msg);
} }
}; };
for (int i = 1; i < argc; ++i) for (int i = 1; i < argc; ++i) {
{
char* arg = argv[i]; char* arg = argv[i];
char* next = argv[i+1]; char* next = argv[i + 1];
if (strcmp(arg, "--infile") == 0) if (strcmp(arg, "--infile") == 0) {
{
check_arg(next, "--infile takes an argument"); check_arg(next, "--infile takes an argument");
infilename = next; infilename = next;
++i; ++i;
} } else if (strcmp(arg, "--password") == 0) {
else if (strcmp(arg, "--password") == 0)
{
check_arg(next, "--password takes an argument"); check_arg(next, "--password takes an argument");
password = next; password = next;
++i; ++i;
} } else if (strcmp(arg, "--attachment") == 0) {
else if (strcmp(arg, "--attachment") == 0)
{
check_arg(next, "--attachment takes an argument"); check_arg(next, "--attachment takes an argument");
attachment = next; attachment = next;
++i; ++i;
} } else if (strcmp(arg, "--outfile") == 0) {
else if (strcmp(arg, "--outfile") == 0)
{
check_arg(next, "--outfile takes an argument"); check_arg(next, "--outfile takes an argument");
outfilename = next; outfilename = next;
++i; ++i;
} } else if (strcmp(arg, "--mimetype") == 0) {
else if (strcmp(arg, "--mimetype") == 0)
{
check_arg(next, "--mimetype takes an argument"); check_arg(next, "--mimetype takes an argument");
mimetype = next; mimetype = next;
++i; ++i;
} } else {
else
{
usage("unknown argument " + std::string(arg)); usage("unknown argument " + std::string(arg));
} }
} }
if (! (infilename && attachment && outfilename)) if (!(infilename && attachment && outfilename)) {
{
usage("required arguments were not provided"); usage("required arguments were not provided");
} }
try try {
{
process(infilename, password, attachment, mimetype, outfilename); process(infilename, password, attachment, mimetype, outfilename);
} } catch (std::exception& e) {
catch (std::exception &e) std::cerr << whoami << " exception: " << e.what() << std::endl;
{
std::cerr << whoami << " exception: "
<< e.what() << std::endl;
exit(2); exit(2);
} }

View File

@ -1,12 +1,12 @@
#include <iostream>
#include <string.h>
#include <stdlib.h>
#include <qpdf/QPDF.hh>
#include <qpdf/QPDFPageDocumentHelper.hh>
#include <qpdf/QPDFOutlineDocumentHelper.hh>
#include <qpdf/QUtil.hh>
#include <qpdf/QIntC.hh> #include <qpdf/QIntC.hh>
#include <qpdf/QPDF.hh>
#include <qpdf/QPDFOutlineDocumentHelper.hh>
#include <qpdf/QPDFPageDocumentHelper.hh>
#include <qpdf/QTC.hh> #include <qpdf/QTC.hh>
#include <qpdf/QUtil.hh>
#include <iostream>
#include <stdlib.h>
#include <string.h>
// This program demonstrates extraction of bookmarks using the qpdf // This program demonstrates extraction of bookmarks using the qpdf
// outlines API. Note that all the information shown by this program // outlines API. Note that all the information shown by this program
@ -20,67 +20,62 @@ static bool show_open = false;
static bool show_targets = false; static bool show_targets = false;
static std::map<QPDFObjGen, int> page_map; static std::map<QPDFObjGen, int> page_map;
void usage() void
usage()
{ {
std::cerr << "Usage: " << whoami << " [options] file.pdf [password]" std::cerr
<< std::endl << "Usage: " << whoami << " [options] file.pdf [password]" << std::endl
<< "Options:" << std::endl << "Options:" << std::endl
<< " --numbers give bookmarks outline-style numbers" << " --numbers give bookmarks outline-style numbers"
<< std::endl << std::endl
<< " --lines draw lines to show bookmark hierarchy" << " --lines draw lines to show bookmark hierarchy"
<< std::endl << std::endl
<< " --show-open indicate whether a bookmark is initially open" << " --show-open indicate whether a bookmark is initially open"
<< std::endl << std::endl
<< " --show-targets show target if possible" << " --show-targets show target if possible" << std::endl;
<< std::endl;
exit(2); exit(2);
} }
void print_lines(std::vector<int>& numbers) void
print_lines(std::vector<int>& numbers)
{ {
for (unsigned int i = 0; i < numbers.size() - 1; ++i) for (unsigned int i = 0; i < numbers.size() - 1; ++i) {
{ if (numbers.at(i)) {
if (numbers.at(i))
{
std::cout << "| "; std::cout << "| ";
} } else {
else
{
std::cout << " "; std::cout << " ";
} }
} }
} }
void generate_page_map(QPDF& qpdf) void
generate_page_map(QPDF& qpdf)
{ {
QPDFPageDocumentHelper dh(qpdf); QPDFPageDocumentHelper dh(qpdf);
int n = 0; int n = 0;
for (auto const& page : dh.getAllPages()) for (auto const& page : dh.getAllPages()) {
{
page_map[page.getObjectHandle().getObjGen()] = ++n; page_map[page.getObjectHandle().getObjGen()] = ++n;
} }
} }
void show_bookmark_details(QPDFOutlineObjectHelper outline, void
std::vector<int> numbers) show_bookmark_details(QPDFOutlineObjectHelper outline, std::vector<int> numbers)
{ {
// No default so gcc will warn on missing tag // No default so gcc will warn on missing tag
switch (style) switch (style) {
{ case st_none:
case st_none:
QTC::TC("examples", "pdf-bookmarks none"); QTC::TC("examples", "pdf-bookmarks none");
break; break;
case st_numbers: case st_numbers:
QTC::TC("examples", "pdf-bookmarks numbers"); QTC::TC("examples", "pdf-bookmarks numbers");
for (auto const& number : numbers) for (auto const& number : numbers) {
{
std::cout << number << "."; std::cout << number << ".";
} }
std::cout << " "; std::cout << " ";
break; break;
case st_lines: case st_lines:
QTC::TC("examples", "pdf-bookmarks lines"); QTC::TC("examples", "pdf-bookmarks lines");
print_lines(numbers); print_lines(numbers);
std::cout << "|" << std::endl; std::cout << "|" << std::endl;
@ -89,42 +84,32 @@ void show_bookmark_details(QPDFOutlineObjectHelper outline,
break; break;
} }
if (show_open) if (show_open) {
{
int count = outline.getCount(); int count = outline.getCount();
if (count) if (count) {
{
QTC::TC("examples", "pdf-bookmarks has count"); QTC::TC("examples", "pdf-bookmarks has count");
if (count > 0) if (count > 0) {
{
// hierarchy is open at this point // hierarchy is open at this point
QTC::TC("examples", "pdf-bookmarks open"); QTC::TC("examples", "pdf-bookmarks open");
std::cout << "(v) "; std::cout << "(v) ";
} } else {
else
{
QTC::TC("examples", "pdf-bookmarks closed"); QTC::TC("examples", "pdf-bookmarks closed");
std::cout << "(>) "; std::cout << "(>) ";
} }
} } else {
else
{
QTC::TC("examples", "pdf-bookmarks no count"); QTC::TC("examples", "pdf-bookmarks no count");
std::cout << "( ) "; std::cout << "( ) ";
} }
} }
if (show_targets) if (show_targets) {
{
QTC::TC("examples", "pdf-bookmarks targets"); QTC::TC("examples", "pdf-bookmarks targets");
std::string target = "unknown"; std::string target = "unknown";
QPDFObjectHandle dest_page = outline.getDestPage(); QPDFObjectHandle dest_page = outline.getDestPage();
if (! dest_page.isNull()) if (!dest_page.isNull()) {
{
QTC::TC("examples", "pdf-bookmarks dest"); QTC::TC("examples", "pdf-bookmarks dest");
QPDFObjGen og = dest_page.getObjGen(); QPDFObjGen og = dest_page.getObjGen();
if (page_map.count(og)) if (page_map.count(og)) {
{
target = QUtil::int_to_string(page_map[og]); target = QUtil::int_to_string(page_map[og]);
} }
} }
@ -134,8 +119,9 @@ void show_bookmark_details(QPDFOutlineObjectHelper outline,
std::cout << outline.getTitle() << std::endl; std::cout << outline.getTitle() << std::endl;
} }
void extract_bookmarks(std::vector<QPDFOutlineObjectHelper> outlines, void
std::vector<int>& numbers) extract_bookmarks(
std::vector<QPDFOutlineObjectHelper> outlines, std::vector<int>& numbers)
{ {
// For style == st_numbers, numbers.at(n) contains the numerical // For style == st_numbers, numbers.at(n) contains the numerical
// label for the outline, so we count up from 1. // label for the outline, so we count up from 1.
@ -144,8 +130,7 @@ void extract_bookmarks(std::vector<QPDFOutlineObjectHelper> outlines,
// is, so we count up to zero. // is, so we count up to zero.
numbers.push_back( numbers.push_back(
(style == st_lines) ? -QIntC::to_int(outlines.size()) : 0); (style == st_lines) ? -QIntC::to_int(outlines.size()) : 0);
for (auto& outline : outlines) for (auto& outline : outlines) {
{
++(numbers.back()); ++(numbers.back());
show_bookmark_details(outline, numbers); show_bookmark_details(outline, numbers);
extract_bookmarks(outline.getKids(), numbers); extract_bookmarks(outline.getKids(), numbers);
@ -153,87 +138,64 @@ void extract_bookmarks(std::vector<QPDFOutlineObjectHelper> outlines,
numbers.pop_back(); numbers.pop_back();
} }
int main(int argc, char* argv[]) int
main(int argc, char* argv[])
{ {
whoami = QUtil::getWhoami(argv[0]); whoami = QUtil::getWhoami(argv[0]);
if ((argc == 2) && (strcmp(argv[1], "--version") == 0)) if ((argc == 2) && (strcmp(argv[1], "--version") == 0)) {
{
std::cout << whoami << " version 1.5" << std::endl; std::cout << whoami << " version 1.5" << std::endl;
exit(0); exit(0);
} }
int arg; int arg;
for (arg = 1; arg < argc; ++arg) for (arg = 1; arg < argc; ++arg) {
{ if (argv[arg][0] == '-') {
if (argv[arg][0] == '-') if (strcmp(argv[arg], "--numbers") == 0) {
{
if (strcmp(argv[arg], "--numbers") == 0)
{
style = st_numbers; style = st_numbers;
} } else if (strcmp(argv[arg], "--lines") == 0) {
else if (strcmp(argv[arg], "--lines") == 0)
{
style = st_lines; style = st_lines;
} } else if (strcmp(argv[arg], "--show-open") == 0) {
else if (strcmp(argv[arg], "--show-open") == 0)
{
show_open = true; show_open = true;
} } else if (strcmp(argv[arg], "--show-targets") == 0) {
else if (strcmp(argv[arg], "--show-targets") == 0)
{
show_targets = true; show_targets = true;
} } else {
else
{
usage(); usage();
} }
} } else {
else
{
break; break;
} }
} }
if (arg >= argc) if (arg >= argc) {
{
usage(); usage();
} }
char const* filename = argv[arg++]; char const* filename = argv[arg++];
char const* password = ""; char const* password = "";
if (arg < argc) if (arg < argc) {
{
password = argv[arg++]; password = argv[arg++];
} }
if (arg != argc) if (arg != argc) {
{
usage(); usage();
} }
try try {
{
QPDF qpdf; QPDF qpdf;
qpdf.processFile(filename, password); qpdf.processFile(filename, password);
QPDFOutlineDocumentHelper odh(qpdf); QPDFOutlineDocumentHelper odh(qpdf);
if (odh.hasOutlines()) if (odh.hasOutlines()) {
{
std::vector<int> numbers; std::vector<int> numbers;
if (show_targets) if (show_targets) {
{
generate_page_map(qpdf); generate_page_map(qpdf);
} }
extract_bookmarks(odh.getTopLevelOutlines(), numbers); extract_bookmarks(odh.getTopLevelOutlines(), numbers);
} } else {
else
{
std::cout << filename << " has no bookmarks" << std::endl; std::cout << filename << " has no bookmarks" << std::endl;
} }
} } catch (std::exception& e) {
catch (std::exception &e)
{
std::cerr << whoami << " processing file " << filename << ": " std::cerr << whoami << " processing file " << filename << ": "
<< e.what() << std::endl; << e.what() << std::endl;
exit(2); exit(2);

View File

@ -10,7 +10,8 @@
static char const* whoami = 0; static char const* whoami = 0;
static void usage() static void
usage()
{ {
fprintf(stderr, "Usage: %s infile infile-password outfile\n", whoami); fprintf(stderr, "Usage: %s infile infile-password outfile\n", whoami);
exit(2); exit(2);
@ -33,12 +34,9 @@ modify_file(qpdf_data qpdf)
/* 0 is never a valid qpdf_oh */ /* 0 is never a valid qpdf_oh */
qpdf_oh pagemode = 0; qpdf_oh pagemode = 0;
if (qpdf_oh_is_dictionary( if (qpdf_oh_is_dictionary(
qpdf, qpdf_oh_get_key(qpdf, root, "/PageLabels"))) qpdf, qpdf_oh_get_key(qpdf, root, "/PageLabels"))) {
{
pagemode = qpdf_oh_new_name(qpdf, "/UseOutlines"); pagemode = qpdf_oh_new_name(qpdf, "/UseOutlines");
} } else {
else
{
pagemode = qpdf_oh_new_null(qpdf); pagemode = qpdf_oh_new_null(qpdf);
} }
qpdf_oh_replace_or_remove_key(qpdf, root, "/PageMode", pagemode); qpdf_oh_replace_or_remove_key(qpdf, root, "/PageMode", pagemode);
@ -46,7 +44,8 @@ modify_file(qpdf_data qpdf)
return QPDF_TRUE; return QPDF_TRUE;
} }
int main(int argc, char* argv[]) int
main(int argc, char* argv[])
{ {
char* infile = NULL; char* infile = NULL;
char* password = NULL; char* password = NULL;
@ -56,21 +55,15 @@ int main(int argc, char* argv[])
int errors = 0; int errors = 0;
char* p = 0; char* p = 0;
if ((p = strrchr(argv[0], '/')) != NULL) if ((p = strrchr(argv[0], '/')) != NULL) {
{
whoami = p + 1; whoami = p + 1;
} } else if ((p = strrchr(argv[0], '\\')) != NULL) {
else if ((p = strrchr(argv[0], '\\')) != NULL)
{
whoami = p + 1; whoami = p + 1;
} } else {
else
{
whoami = argv[0]; whoami = argv[0];
} }
if (argc != 4) if (argc != 4) {
{
usage(); usage();
} }
@ -80,33 +73,29 @@ int main(int argc, char* argv[])
if (((qpdf_read(qpdf, infile, password) & QPDF_ERRORS) == 0) && if (((qpdf_read(qpdf, infile, password) & QPDF_ERRORS) == 0) &&
modify_file(qpdf) && modify_file(qpdf) &&
((qpdf_init_write(qpdf, outfile) & QPDF_ERRORS) == 0)) ((qpdf_init_write(qpdf, outfile) & QPDF_ERRORS) == 0)) {
{
/* Use static ID for testing only. For production, a /* Use static ID for testing only. For production, a
* non-static ID is used. See also * non-static ID is used. See also
* qpdf_set_deterministic_ID. */ * qpdf_set_deterministic_ID. */
qpdf_set_static_ID(qpdf, QPDF_TRUE); /* for testing only */ qpdf_set_static_ID(qpdf, QPDF_TRUE); /* for testing only */
qpdf_write(qpdf); qpdf_write(qpdf);
} }
while (qpdf_more_warnings(qpdf)) while (qpdf_more_warnings(qpdf)) {
{
warnings = 1; warnings = 1;
printf("warning: %s\n", printf(
qpdf_get_error_full_text(qpdf, qpdf_next_warning(qpdf))); "warning: %s\n",
qpdf_get_error_full_text(qpdf, qpdf_next_warning(qpdf)));
} }
if (qpdf_has_error(qpdf)) if (qpdf_has_error(qpdf)) {
{
errors = 1; errors = 1;
printf("error: %s\n", printf(
qpdf_get_error_full_text(qpdf, qpdf_get_error(qpdf))); "error: %s\n",
qpdf_get_error_full_text(qpdf, qpdf_get_error(qpdf)));
} }
qpdf_cleanup(&qpdf); qpdf_cleanup(&qpdf);
if (errors) if (errors) {
{
return 2; return 2;
} } else if (warnings) {
else if (warnings)
{
return 3; return 3;
} }

View File

@ -5,23 +5,23 @@
// //
#include <iostream> #include <iostream>
#include <string.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h>
#include <qpdf/Pl_StdioFile.hh>
#include <qpdf/QPDF.hh> #include <qpdf/QPDF.hh>
#include <qpdf/QPDFObjectHandle.hh>
#include <qpdf/QPDFPageDocumentHelper.hh> #include <qpdf/QPDFPageDocumentHelper.hh>
#include <qpdf/QPDFPageObjectHelper.hh> #include <qpdf/QPDFPageObjectHelper.hh>
#include <qpdf/QUtil.hh> #include <qpdf/QUtil.hh>
#include <qpdf/QPDFObjectHandle.hh>
#include <qpdf/Pl_StdioFile.hh>
static char const* whoami = 0; static char const* whoami = 0;
void usage() void
usage()
{ {
std::cerr << "Usage: " << whoami << " infile" << std::endl std::cerr << "Usage: " << whoami << " infile" << std::endl
<< "Applies token filters to infile" << "Applies token filters to infile" << std::endl;
<< std::endl;
exit(2); exit(2);
} }
@ -47,8 +47,7 @@ void
StringCounter::handleToken(QPDFTokenizer::Token const& token) StringCounter::handleToken(QPDFTokenizer::Token const& token)
{ {
// Count string tokens // Count string tokens
if (token.getType() == QPDFTokenizer::tt_string) if (token.getType() == QPDFTokenizer::tt_string) {
{
++this->count; ++this->count;
} }
// Preserve input verbatim by passing each token to any specified // Preserve input verbatim by passing each token to any specified
@ -71,36 +70,31 @@ StringCounter::getCount() const
return this->count; return this->count;
} }
int main(int argc, char* argv[]) int
main(int argc, char* argv[])
{ {
whoami = QUtil::getWhoami(argv[0]); whoami = QUtil::getWhoami(argv[0]);
if (argc != 2) if (argc != 2) {
{
usage(); usage();
} }
char const* infilename = argv[1]; char const* infilename = argv[1];
try try {
{
QPDF pdf; QPDF pdf;
pdf.processFile(infilename); pdf.processFile(infilename);
int pageno = 0; int pageno = 0;
for (auto& page : QPDFPageDocumentHelper(pdf).getAllPages()) for (auto& page : QPDFPageDocumentHelper(pdf).getAllPages()) {
{
++pageno; ++pageno;
// Pass the contents of a page through our string counter. // Pass the contents of a page through our string counter.
// If it's an even page, capture the output. This // If it's an even page, capture the output. This
// illustrates that you may capture any output generated // illustrates that you may capture any output generated
// by the filter, or you may ignore it. // by the filter, or you may ignore it.
StringCounter counter; StringCounter counter;
if (pageno % 2) if (pageno % 2) {
{
// Ignore output for odd pages. // Ignore output for odd pages.
page.filterContents(&counter); page.filterContents(&counter);
} } else {
else
{
// Write output to stdout for even pages. // Write output to stdout for even pages.
Pl_StdioFile out("stdout", stdout); Pl_StdioFile out("stdout", stdout);
std::cout << "% Contents of page " << pageno << std::endl; std::cout << "% Contents of page " << pageno << std::endl;
@ -110,9 +104,7 @@ int main(int argc, char* argv[])
std::cout << "Page " << pageno std::cout << "Page " << pageno
<< ": strings = " << counter.getCount() << std::endl; << ": strings = " << counter.getCount() << std::endl;
} }
} } catch (std::exception& e) {
catch (std::exception& e)
{
std::cerr << whoami << ": " << e.what() << std::endl; std::cerr << whoami << ": " << e.what() << std::endl;
exit(2); exit(2);
} }

View File

@ -5,20 +5,20 @@
// StreamDataProvider with different types of filters. // StreamDataProvider with different types of filters.
// //
#include <qpdf/Pl_Buffer.hh>
#include <qpdf/Pl_DCT.hh>
#include <qpdf/Pl_RunLength.hh>
#include <qpdf/QIntC.hh>
#include <qpdf/QPDF.hh> #include <qpdf/QPDF.hh>
#include <qpdf/QPDFObjectHandle.hh>
#include <qpdf/QPDFPageDocumentHelper.hh> #include <qpdf/QPDFPageDocumentHelper.hh>
#include <qpdf/QPDFPageObjectHelper.hh> #include <qpdf/QPDFPageObjectHelper.hh>
#include <qpdf/QPDFWriter.hh> #include <qpdf/QPDFWriter.hh>
#include <qpdf/QPDFObjectHandle.hh>
#include <qpdf/QUtil.hh> #include <qpdf/QUtil.hh>
#include <qpdf/Pl_Buffer.hh>
#include <qpdf/Pl_RunLength.hh>
#include <qpdf/Pl_DCT.hh>
#include <qpdf/QIntC.hh>
#include <iostream> #include <iostream>
#include <memory> #include <memory>
#include <string.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h>
static char const* whoami = 0; static char const* whoami = 0;
@ -27,11 +27,10 @@ static char const* whoami = 0;
class ImageProvider: public QPDFObjectHandle::StreamDataProvider class ImageProvider: public QPDFObjectHandle::StreamDataProvider
{ {
public: public:
ImageProvider(std::string const& color_space, ImageProvider(std::string const& color_space, std::string const& filter);
std::string const& filter);
virtual ~ImageProvider(); virtual ~ImageProvider();
virtual void provideStreamData(int objid, int generation, virtual void
Pipeline* pipeline); provideStreamData(int objid, int generation, Pipeline* pipeline);
size_t getWidth() const; size_t getWidth() const;
size_t getHeight() const; size_t getHeight() const;
@ -45,8 +44,8 @@ class ImageProvider: public QPDFObjectHandle::StreamDataProvider
J_COLOR_SPACE j_color_space; J_COLOR_SPACE j_color_space;
}; };
ImageProvider::ImageProvider(std::string const& color_space, ImageProvider::ImageProvider(
std::string const& filter) : std::string const& color_space, std::string const& filter) :
width(400), width(400),
stripe_height(80), stripe_height(80),
color_space(color_space), color_space(color_space),
@ -54,8 +53,7 @@ ImageProvider::ImageProvider(std::string const& color_space,
n_stripes(6), n_stripes(6),
j_color_space(JCS_UNKNOWN) j_color_space(JCS_UNKNOWN)
{ {
if (color_space == "/DeviceCMYK") if (color_space == "/DeviceCMYK") {
{
j_color_space = JCS_CMYK; j_color_space = JCS_CMYK;
stripes.push_back(std::string("\xff\x00\x00\x00", 4)); stripes.push_back(std::string("\xff\x00\x00\x00", 4));
stripes.push_back(std::string("\x00\xff\x00\x00", 4)); stripes.push_back(std::string("\x00\xff\x00\x00", 4));
@ -63,9 +61,7 @@ ImageProvider::ImageProvider(std::string const& color_space,
stripes.push_back(std::string("\xff\x00\xff\x00", 4)); stripes.push_back(std::string("\xff\x00\xff\x00", 4));
stripes.push_back(std::string("\xff\xff\x00\x00", 4)); stripes.push_back(std::string("\xff\xff\x00\x00", 4));
stripes.push_back(std::string("\x00\x00\x00\xff", 4)); stripes.push_back(std::string("\x00\x00\x00\xff", 4));
} } else if (color_space == "/DeviceRGB") {
else if (color_space == "/DeviceRGB")
{
j_color_space = JCS_RGB; j_color_space = JCS_RGB;
stripes.push_back(std::string("\xff\x00\x00", 3)); stripes.push_back(std::string("\xff\x00\x00", 3));
stripes.push_back(std::string("\x00\xff\x00", 3)); stripes.push_back(std::string("\x00\xff\x00", 3));
@ -73,9 +69,7 @@ ImageProvider::ImageProvider(std::string const& color_space,
stripes.push_back(std::string("\xff\x00\xff", 3)); stripes.push_back(std::string("\xff\x00\xff", 3));
stripes.push_back(std::string("\xff\xff\x00", 3)); stripes.push_back(std::string("\xff\xff\x00", 3));
stripes.push_back(std::string("\x00\x00\x00", 3)); stripes.push_back(std::string("\x00\x00\x00", 3));
} } else if (color_space == "/DeviceGray") {
else if (color_space == "/DeviceGray")
{
j_color_space = JCS_GRAYSCALE; j_color_space = JCS_GRAYSCALE;
stripes.push_back(std::string("\xee", 1)); stripes.push_back(std::string("\xee", 1));
stripes.push_back(std::string("\xcc", 1)); stripes.push_back(std::string("\xcc", 1));
@ -103,34 +97,31 @@ ImageProvider::getHeight() const
} }
void void
ImageProvider::provideStreamData(int objid, int generation, ImageProvider::provideStreamData(int objid, int generation, Pipeline* pipeline)
Pipeline* pipeline)
{ {
std::vector<std::shared_ptr<Pipeline>> to_delete; std::vector<std::shared_ptr<Pipeline>> to_delete;
Pipeline* p = pipeline; Pipeline* p = pipeline;
std::shared_ptr<Pipeline> p_new; std::shared_ptr<Pipeline> p_new;
if (filter == "/DCTDecode") if (filter == "/DCTDecode") {
{
p_new = std::make_shared<Pl_DCT>( p_new = std::make_shared<Pl_DCT>(
"image encoder", pipeline, "image encoder",
QIntC::to_uint(width), QIntC::to_uint(getHeight()), pipeline,
QIntC::to_int(stripes[0].length()), j_color_space); QIntC::to_uint(width),
QIntC::to_uint(getHeight()),
QIntC::to_int(stripes[0].length()),
j_color_space);
to_delete.push_back(p_new); to_delete.push_back(p_new);
p = p_new.get(); p = p_new.get();
} } else if (filter == "/RunLengthDecode") {
else if (filter == "/RunLengthDecode")
{
p_new = std::make_shared<Pl_RunLength>( p_new = std::make_shared<Pl_RunLength>(
"image encoder", pipeline, Pl_RunLength::a_encode); "image encoder", pipeline, Pl_RunLength::a_encode);
to_delete.push_back(p_new); to_delete.push_back(p_new);
p = p_new.get(); p = p_new.get();
} }
for (size_t i = 0; i < n_stripes; ++i) for (size_t i = 0; i < n_stripes; ++i) {
{ for (size_t j = 0; j < width * stripe_height; ++j) {
for (size_t j = 0; j < width * stripe_height; ++j)
{
p->write( p->write(
QUtil::unsigned_char_pointer(stripes[i].c_str()), QUtil::unsigned_char_pointer(stripes[i].c_str()),
stripes[i].length()); stripes[i].length());
@ -139,36 +130,43 @@ ImageProvider::provideStreamData(int objid, int generation,
p->finish(); p->finish();
} }
void usage() void
usage()
{ {
std::cerr << "Usage: " << whoami << " filename" << std::endl std::cerr << "Usage: " << whoami << " filename" << std::endl
<< "Creates a simple PDF and writes it to filename" << std::endl; << "Creates a simple PDF and writes it to filename" << std::endl;
exit(2); exit(2);
} }
static QPDFObjectHandle createPageContents(QPDF& pdf, std::string const& text) static QPDFObjectHandle
createPageContents(QPDF& pdf, std::string const& text)
{ {
// Create a stream that displays our image and the given text in // Create a stream that displays our image and the given text in
// our font. // our font.
std::string contents = std::string contents = "BT /F1 24 Tf 72 320 Td (" + text +
"BT /F1 24 Tf 72 320 Td (" + text + ") Tj ET\n" ") Tj ET\n"
"q 244 0 0 144 184 100 cm /Im1 Do Q\n"; "q 244 0 0 144 184 100 cm /Im1 Do Q\n";
return QPDFObjectHandle::newStream(&pdf, contents); return QPDFObjectHandle::newStream(&pdf, contents);
} }
QPDFObjectHandle newName(std::string const& name) QPDFObjectHandle
newName(std::string const& name)
{ {
return QPDFObjectHandle::newName(name); return QPDFObjectHandle::newName(name);
} }
QPDFObjectHandle newInteger(size_t val) QPDFObjectHandle
newInteger(size_t val)
{ {
return QPDFObjectHandle::newInteger(QIntC::to_int(val)); return QPDFObjectHandle::newInteger(QIntC::to_int(val));
} }
void add_page(QPDFPageDocumentHelper& dh, QPDFObjectHandle font, void
std::string const& color_space, add_page(
std::string const& filter) QPDFPageDocumentHelper& dh,
QPDFObjectHandle font,
std::string const& color_space,
std::string const& filter)
{ {
QPDF& pdf(dh.getQPDF()); QPDF& pdf(dh.getQPDF());
@ -193,9 +191,8 @@ void add_page(QPDFPageDocumentHelper& dh, QPDFObjectHandle font,
image.replaceDict(image_dict); image.replaceDict(image_dict);
// Provide the stream data. // Provide the stream data.
image.replaceStreamData(provider, image.replaceStreamData(
QPDFObjectHandle::parse(filter), provider, QPDFObjectHandle::parse(filter), QPDFObjectHandle::newNull());
QPDFObjectHandle::newNull());
// Create direct objects as needed by the page dictionary. // Create direct objects as needed by the page dictionary.
QPDFObjectHandle procset = "[/PDF /Text /ImageC]"_qpdf; QPDFObjectHandle procset = "[/PDF /Text /ImageC]"_qpdf;
@ -212,15 +209,14 @@ void add_page(QPDFPageDocumentHelper& dh, QPDFObjectHandle font,
resources.replaceKey("/XObject", xobject); resources.replaceKey("/XObject", xobject);
// Create the page content stream // Create the page content stream
QPDFObjectHandle contents = createPageContents( QPDFObjectHandle contents =
pdf, color_space + " with filter " + filter); createPageContents(pdf, color_space + " with filter " + filter);
// Create the page dictionary // Create the page dictionary
QPDFObjectHandle page = pdf.makeIndirectObject( QPDFObjectHandle page = pdf.makeIndirectObject("<<"
"<<" " /Type /Page"
" /Type /Page" " /MediaBox [0 0 612 392]"
" /MediaBox [0 0 612 392]" ">>"_qpdf);
">>"_qpdf);
page.replaceKey("/Contents", contents); page.replaceKey("/Contents", contents);
page.replaceKey("/Resources", resources); page.replaceKey("/Resources", resources);
@ -228,9 +224,11 @@ void add_page(QPDFPageDocumentHelper& dh, QPDFObjectHandle font,
dh.addPage(page, false); dh.addPage(page, false);
} }
static void check(char const* filename, static void
std::vector<std::string> const& color_spaces, check(
std::vector<std::string> const& filters) char const* filename,
std::vector<std::string> const& color_spaces,
std::vector<std::string> const& filters)
{ {
// Each stream is compressed the way it is supposed to be. We will // Each stream is compressed the way it is supposed to be. We will
// add additional tests in qpdf.test to exercise QPDFWriter more // add additional tests in qpdf.test to exercise QPDFWriter more
@ -253,17 +251,14 @@ static void check(char const* filename,
QPDF pdf; QPDF pdf;
pdf.processFile(filename); pdf.processFile(filename);
auto pages = QPDFPageDocumentHelper(pdf).getAllPages(); auto pages = QPDFPageDocumentHelper(pdf).getAllPages();
if (n_color_spaces * n_filters != pages.size()) if (n_color_spaces * n_filters != pages.size()) {
{
throw std::logic_error("incorrect number of pages"); throw std::logic_error("incorrect number of pages");
} }
size_t pageno = 1; size_t pageno = 1;
bool errors = false; bool errors = false;
for (auto& page : pages) for (auto& page : pages) {
{
auto images = page.getImages(); auto images = page.getImages();
if (images.size() != 1) if (images.size() != 1) {
{
throw std::logic_error("incorrect number of images on page"); throw std::logic_error("incorrect number of images on page");
} }
@ -273,8 +268,7 @@ static void check(char const* filename,
std::string desired_filter = filters[(pageno - 1) % n_filters]; std::string desired_filter = filters[(pageno - 1) % n_filters];
// In the default mode, QPDFWriter will compress with // In the default mode, QPDFWriter will compress with
// /FlateDecode if no filters are provided. // /FlateDecode if no filters are provided.
if (desired_filter == "null") if (desired_filter == "null") {
{
desired_filter = "/FlateDecode"; desired_filter = "/FlateDecode";
} }
QPDFObjectHandle image = images.begin()->second; QPDFObjectHandle image = images.begin()->second;
@ -282,40 +276,34 @@ static void check(char const* filename,
QPDFObjectHandle color_space = image_dict.getKey("/ColorSpace"); QPDFObjectHandle color_space = image_dict.getKey("/ColorSpace");
QPDFObjectHandle filter = image_dict.getKey("/Filter"); QPDFObjectHandle filter = image_dict.getKey("/Filter");
bool this_errors = false; bool this_errors = false;
if (! filter.isNameAndEquals(desired_filter)) if (!filter.isNameAndEquals(desired_filter)) {
{
this_errors = errors = true; this_errors = errors = true;
std::cout << "page " << pageno << ": expected filter " std::cout << "page " << pageno << ": expected filter "
<< desired_filter << "; actual filter = " << desired_filter
<< filter.unparse() << std::endl; << "; actual filter = " << filter.unparse() << std::endl;
} }
if (! color_space.isNameAndEquals(desired_color_space)) if (!color_space.isNameAndEquals(desired_color_space)) {
{
this_errors = errors = true; this_errors = errors = true;
std::cout << "page " << pageno << ": expected color space " std::cout << "page " << pageno << ": expected color space "
<< desired_color_space << "; actual color space = " << desired_color_space
<< color_space.unparse() << std::endl; << "; actual color space = " << color_space.unparse()
<< std::endl;
} }
if (! this_errors) if (!this_errors) {
{
// Check image data // Check image data
auto actual_data = auto actual_data = image.getStreamData(qpdf_dl_all);
image.getStreamData(qpdf_dl_all);
ImageProvider* p = new ImageProvider(desired_color_space, "null"); ImageProvider* p = new ImageProvider(desired_color_space, "null");
PointerHolder<QPDFObjectHandle::StreamDataProvider> provider(p); PointerHolder<QPDFObjectHandle::StreamDataProvider> provider(p);
Pl_Buffer b_p("get image data"); Pl_Buffer b_p("get image data");
provider->provideStreamData(0, 0, &b_p); provider->provideStreamData(0, 0, &b_p);
PointerHolder<Buffer> desired_data(b_p.getBuffer()); PointerHolder<Buffer> desired_data(b_p.getBuffer());
if (desired_data->getSize() != actual_data->getSize()) if (desired_data->getSize() != actual_data->getSize()) {
{ std::cout << "page " << pageno << ": image data length mismatch"
std::cout << "page " << pageno << std::endl;
<< ": image data length mismatch" << std::endl;
this_errors = errors = true; this_errors = errors = true;
} } else {
else
{
// Compare bytes. For JPEG, allow a certain number of // Compare bytes. For JPEG, allow a certain number of
// the bytes to be off desired by more than a given // the bytes to be off desired by more than a given
// tolerance. Any of the samples may be a little off // tolerance. Any of the samples may be a little off
@ -326,25 +314,20 @@ static void check(char const* filename,
unsigned char const* desired_bytes = desired_data->getBuffer(); unsigned char const* desired_bytes = desired_data->getBuffer();
size_t len = actual_data->getSize(); size_t len = actual_data->getSize();
unsigned int mismatches = 0; unsigned int mismatches = 0;
int tolerance = ( int tolerance = (desired_filter == "/DCTDecode" ? 10 : 0);
desired_filter == "/DCTDecode" ? 10 : 0); size_t threshold =
size_t threshold = ( (desired_filter == "/DCTDecode" ? len / 40U : 0);
desired_filter == "/DCTDecode" ? len / 40U : 0); for (size_t i = 0; i < len; ++i) {
for (size_t i = 0; i < len; ++i)
{
int delta = actual_bytes[i] - desired_bytes[i]; int delta = actual_bytes[i] - desired_bytes[i];
if ((delta > tolerance) || (delta < -tolerance)) if ((delta > tolerance) || (delta < -tolerance)) {
{
++mismatches; ++mismatches;
} }
} }
if (mismatches > threshold) if (mismatches > threshold) {
{ std::cout << "page " << pageno << ": "
std::cout << "page " << pageno << desired_color_space << ", " << desired_filter
<< ": " << desired_color_space << ", " << ": mismatches: " << mismatches << " of " << len
<< desired_filter << std::endl;
<< ": mismatches: " << mismatches
<< " of " << len << std::endl;
this_errors = errors = true; this_errors = errors = true;
} }
} }
@ -352,17 +335,15 @@ static void check(char const* filename,
++pageno; ++pageno;
} }
if (errors) if (errors) {
{
throw std::logic_error("errors found"); throw std::logic_error("errors found");
} } else {
else
{
std::cout << "all checks passed" << std::endl; std::cout << "all checks passed" << std::endl;
} }
} }
static void create_pdf(char const* filename) static void
create_pdf(char const* filename)
{ {
QPDF pdf; QPDF pdf;
@ -371,14 +352,13 @@ static void create_pdf(char const* filename)
// Add an indirect object to contain a font descriptor for the // Add an indirect object to contain a font descriptor for the
// built-in Helvetica font. // built-in Helvetica font.
QPDFObjectHandle font = pdf.makeIndirectObject( QPDFObjectHandle font = pdf.makeIndirectObject("<<"
"<<" " /Type /Font"
" /Type /Font" " /Subtype /Type1"
" /Subtype /Type1" " /Name /F1"
" /Name /F1" " /BaseFont /Helvetica"
" /BaseFont /Helvetica" " /Encoding /WinAnsiEncoding"
" /Encoding /WinAnsiEncoding" ">>"_qpdf);
">>"_qpdf);
std::vector<std::string> color_spaces; std::vector<std::string> color_spaces;
color_spaces.push_back("/DeviceCMYK"); color_spaces.push_back("/DeviceCMYK");
@ -389,10 +369,8 @@ static void create_pdf(char const* filename)
filters.push_back("/DCTDecode"); filters.push_back("/DCTDecode");
filters.push_back("/RunLengthDecode"); filters.push_back("/RunLengthDecode");
QPDFPageDocumentHelper dh(pdf); QPDFPageDocumentHelper dh(pdf);
for (auto const& color_space : color_spaces) for (auto const& color_space : color_spaces) {
{ for (auto const& filter : filters) {
for (auto const& filter : filters)
{
add_page(dh, font, color_space, filter); add_page(dh, font, color_space, filter);
} }
} }
@ -405,22 +383,19 @@ static void create_pdf(char const* filename)
check(filename, color_spaces, filters); check(filename, color_spaces, filters);
} }
int main(int argc, char* argv[]) int
main(int argc, char* argv[])
{ {
whoami = QUtil::getWhoami(argv[0]); whoami = QUtil::getWhoami(argv[0]);
if (argc != 2) if (argc != 2) {
{
usage(); usage();
} }
char const* filename = argv[1]; char const* filename = argv[1];
try try {
{
create_pdf(filename); create_pdf(filename);
} } catch (std::exception& e) {
catch (std::exception& e)
{
std::cerr << e.what() << std::endl; std::cerr << e.what() << std::endl;
exit(2); exit(2);
} }

View File

@ -1,7 +1,7 @@
#include <qpdf/QPDF.hh> #include <qpdf/QPDF.hh>
#include <qpdf/QUtil.hh>
#include <qpdf/QPDFWriter.hh>
#include <qpdf/QPDFStreamFilter.hh> #include <qpdf/QPDFStreamFilter.hh>
#include <qpdf/QPDFWriter.hh>
#include <qpdf/QUtil.hh>
#include <cstring> #include <cstring>
#include <exception> #include <exception>
@ -39,7 +39,6 @@
static char const* whoami = 0; static char const* whoami = 0;
class Pl_XOR: public Pipeline class Pl_XOR: public Pipeline
{ {
// This class implements a Pipeline for the made-up XOR decoder. // This class implements a Pipeline for the made-up XOR decoder.
@ -66,8 +65,7 @@ Pl_XOR::Pl_XOR(char const* identifier, Pipeline* next, unsigned char key) :
void void
Pl_XOR::write(unsigned char* data, size_t len) Pl_XOR::write(unsigned char* data, size_t len)
{ {
for (size_t i = 0; i < len; ++i) for (size_t i = 0; i < len; ++i) {
{
unsigned char p = data[i] ^ this->key; unsigned char p = data[i] ^ this->key;
getNext()->write(&p, 1); getNext()->write(&p, 1);
} }
@ -118,8 +116,7 @@ SF_XORDecode::setDecodeParms(QPDFObjectHandle decode_parms)
// to handle the /JBIG2Globals key, which points to a stream. See // to handle the /JBIG2Globals key, which points to a stream. See
// comments in SF_XORDecode::registerStream for additional notes // comments in SF_XORDecode::registerStream for additional notes
// on this. // on this.
try try {
{
// Expect /DecodeParms to be a dictionary with a /KeyStream // Expect /DecodeParms to be a dictionary with a /KeyStream
// key that points to a one-byte stream whose single byte is // key that points to a one-byte stream whose single byte is
// the key. If we are successful at retrieving the key, return // the key. If we are successful at retrieving the key, return
@ -129,17 +126,14 @@ SF_XORDecode::setDecodeParms(QPDFObjectHandle decode_parms)
// implementations, look at the classes whose names start with // implementations, look at the classes whose names start with
// SF_ in the qpdf library implementation. // SF_ in the qpdf library implementation.
auto buf = decode_parms.getKey("/KeyStream").getStreamData(); auto buf = decode_parms.getKey("/KeyStream").getStreamData();
if (buf->getSize() != 1) if (buf->getSize() != 1) {
{
return false; return false;
} }
this->key = buf->getBuffer()[0]; this->key = buf->getBuffer()[0];
return true; return true;
} } catch (std::exception& e) {
catch (std::exception& e) std::cerr << "Error extracting key for /XORDecode: " << e.what()
{ << std::endl;
std::cerr << "Error extracting key for /XORDecode: "
<< e.what() << std::endl;
} }
return false; return false;
} }
@ -206,17 +200,19 @@ class StreamReplacer: public QPDFObjectHandle::StreamDataProvider
public: public:
StreamReplacer(QPDF* pdf); StreamReplacer(QPDF* pdf);
virtual ~StreamReplacer() = default; virtual ~StreamReplacer() = default;
virtual void provideStreamData(int objid, int generation, virtual void
Pipeline* pipeline) override; provideStreamData(int objid, int generation, Pipeline* pipeline) override;
void registerStream( void registerStream(
QPDFObjectHandle stream, QPDFObjectHandle stream,
PointerHolder<QPDFObjectHandle::StreamDataProvider> self); PointerHolder<QPDFObjectHandle::StreamDataProvider> self);
private: private:
bool maybeReplace(QPDFObjGen const& og, bool maybeReplace(
QPDFObjectHandle& stream, Pipeline* pipeline, QPDFObjGen const& og,
QPDFObjectHandle* dict_updates); QPDFObjectHandle& stream,
Pipeline* pipeline,
QPDFObjectHandle* dict_updates);
// Hang onto a reference to the QPDF object containing the streams // Hang onto a reference to the QPDF object containing the streams
// we are replacing. We need this to create a new stream. // we are replacing. We need this to create a new stream.
@ -238,10 +234,11 @@ StreamReplacer::StreamReplacer(QPDF* pdf) :
} }
bool bool
StreamReplacer::maybeReplace(QPDFObjGen const& og, StreamReplacer::maybeReplace(
QPDFObjectHandle& stream, QPDFObjGen const& og,
Pipeline* pipeline, QPDFObjectHandle& stream,
QPDFObjectHandle* dict_updates) Pipeline* pipeline,
QPDFObjectHandle* dict_updates)
{ {
// As described in the class comments, this method is called // As described in the class comments, this method is called
// twice. Before writing has started pipeline is nullptr, and // twice. Before writing has started pipeline is nullptr, and
@ -276,8 +273,7 @@ StreamReplacer::maybeReplace(QPDFObjGen const& og,
// density. // density.
auto dict = stream.getDict(); auto dict = stream.getDict();
auto mark = dict.getKey("/DoXOR"); auto mark = dict.getKey("/DoXOR");
if (! (mark.isBool() && mark.getBoolValue())) if (!(mark.isBool() && mark.getBoolValue())) {
{
return false; return false;
} }
@ -288,17 +284,13 @@ StreamReplacer::maybeReplace(QPDFObjGen const& og,
// it's a good idea to make sure we can retrieve the filtered data // it's a good idea to make sure we can retrieve the filtered data
// if we are going to need it later. // if we are going to need it later.
PointerHolder<Buffer> out; PointerHolder<Buffer> out;
try try {
{
out = stream.getStreamData(); out = stream.getStreamData();
} } catch (...) {
catch (...)
{
return false; return false;
} }
if (dict_updates) if (dict_updates) {
{
// It's not safe to make any modifications to any objects // It's not safe to make any modifications to any objects
// during the writing process since the updated objects may // during the writing process since the updated objects may
// have already been written. In this mode, when dict_updates // have already been written. In this mode, when dict_updates
@ -309,16 +301,15 @@ StreamReplacer::maybeReplace(QPDFObjGen const& og,
// changes. For example, an image resampler might change the // changes. For example, an image resampler might change the
// dimensions or other properties of the image. // dimensions or other properties of the image.
dict_updates->replaceKey( dict_updates->replaceKey(
"/OrigLength", QPDFObjectHandle::newInteger( "/OrigLength",
QIntC::to_longlong(out->getSize()))); QPDFObjectHandle::newInteger(QIntC::to_longlong(out->getSize())));
// We are also storing the "key" that we will access when // We are also storing the "key" that we will access when
// writing the data. // writing the data.
this->keys[og] = QIntC::to_uchar( this->keys[og] = QIntC::to_uchar(
(og.getObj() * QIntC::to_int(out->getSize())) & 0xff); (og.getObj() * QIntC::to_int(out->getSize())) & 0xff);
} }
if (pipeline) if (pipeline) {
{
unsigned char key = this->keys[og]; unsigned char key = this->keys[og];
Pl_XOR p("xor", pipeline, key); Pl_XOR p("xor", pipeline, key);
p.write(out->getBuffer(), out->getSize()); p.write(out->getBuffer(), out->getSize());
@ -338,8 +329,7 @@ StreamReplacer::registerStream(
// example, we are just iterating through objects, but if we were // example, we are just iterating through objects, but if we were
// doing something like iterating through images on pages, we // doing something like iterating through images on pages, we
// might realistically encounter the same stream more than once. // might realistically encounter the same stream more than once.
if (this->copied_streams.count(og) > 0) if (this->copied_streams.count(og) > 0) {
{
return; return;
} }
// Store something in copied_streams so that we don't // Store something in copied_streams so that we don't
@ -352,19 +342,14 @@ StreamReplacer::registerStream(
// so, supplies dictionary updates we should make. // so, supplies dictionary updates we should make.
bool should_replace = false; bool should_replace = false;
QPDFObjectHandle dict_updates = QPDFObjectHandle::newDictionary(); QPDFObjectHandle dict_updates = QPDFObjectHandle::newDictionary();
try try {
{
should_replace = maybeReplace(og, stream, nullptr, &dict_updates); should_replace = maybeReplace(og, stream, nullptr, &dict_updates);
} } catch (std::exception& e) {
catch (std::exception& e)
{
stream.warnIfPossible( stream.warnIfPossible(
std::string("exception while attempting to replace: ") + std::string("exception while attempting to replace: ") + e.what());
e.what());
} }
if (should_replace) if (should_replace) {
{
// Copy the stream so we can get to the original data from the // Copy the stream so we can get to the original data from the
// stream data provider. This doesn't actually copy any data, // stream data provider. This doesn't actually copy any data,
// but the copy retains the original stream data after the // but the copy retains the original stream data after the
@ -372,14 +357,13 @@ StreamReplacer::registerStream(
this->copied_streams[og] = stream.copyStream(); this->copied_streams[og] = stream.copyStream();
// Update the stream dictionary with any changes. // Update the stream dictionary with any changes.
auto dict = stream.getDict(); auto dict = stream.getDict();
for (auto const& k: dict_updates.getKeys()) for (auto const& k : dict_updates.getKeys()) {
{
dict.replaceKey(k, dict_updates.getKey(k)); dict.replaceKey(k, dict_updates.getKey(k));
} }
// Create the key stream that will be referenced from // Create the key stream that will be referenced from
// /DecodeParms. We have to do this now since you can't modify // /DecodeParms. We have to do this now since you can't modify
// or create objects during write. // or create objects during write.
char p[1] = { static_cast<char>(this->keys[og]) }; char p[1] = {static_cast<char>(this->keys[og])};
std::string p_str(p, 1); std::string p_str(p, 1);
QPDFObjectHandle dp_stream = QPDFObjectHandle dp_stream =
QPDFObjectHandle::newStream(this->pdf, p_str); QPDFObjectHandle::newStream(this->pdf, p_str);
@ -388,23 +372,19 @@ StreamReplacer::registerStream(
QPDFObjectHandle decode_parms = QPDFObjectHandle decode_parms =
QPDFObjectHandle::newDictionary({{"/KeyStream", dp_stream}}); QPDFObjectHandle::newDictionary({{"/KeyStream", dp_stream}});
stream.replaceStreamData( stream.replaceStreamData(
self, self, QPDFObjectHandle::newName("/XORDecode"), decode_parms);
QPDFObjectHandle::newName("/XORDecode"),
decode_parms);
// Further, if /ProtectXOR = true, we disable filtering on write // Further, if /ProtectXOR = true, we disable filtering on write
// so that QPDFWriter will not decode the stream even though we // so that QPDFWriter will not decode the stream even though we
// have registered a stream filter for /XORDecode. // have registered a stream filter for /XORDecode.
auto protect = dict.getKey("/ProtectXOR"); auto protect = dict.getKey("/ProtectXOR");
if (protect.isBool() && protect.getBoolValue()) if (protect.isBool() && protect.getBoolValue()) {
{
stream.setFilterOnWrite(false); stream.setFilterOnWrite(false);
} }
} }
} }
void void
StreamReplacer::provideStreamData(int objid, int generation, StreamReplacer::provideStreamData(int objid, int generation, Pipeline* pipeline)
Pipeline* pipeline)
{ {
QPDFObjGen og(objid, generation); QPDFObjGen og(objid, generation);
QPDFObjectHandle orig = this->copied_streams[og]; QPDFObjectHandle orig = this->copied_streams[og];
@ -412,8 +392,7 @@ StreamReplacer::provideStreamData(int objid, int generation,
// dict_updates. In this mode, maybeReplace doesn't make any // dict_updates. In this mode, maybeReplace doesn't make any
// changes. We have to hand it the original stream data, which we // changes. We have to hand it the original stream data, which we
// get from copied_streams. // get from copied_streams.
if (! maybeReplace(og, orig, pipeline, nullptr)) if (!maybeReplace(og, orig, pipeline, nullptr)) {
{
// Since this only gets called for streams we already // Since this only gets called for streams we already
// determined we are replacing, a false return would indicate // determined we are replacing, a false return would indicate
// a logic error. // a logic error.
@ -422,8 +401,9 @@ StreamReplacer::provideStreamData(int objid, int generation,
} }
} }
static void process(char const* infilename, char const* outfilename, static void
bool decode_specialized) process(
char const* infilename, char const* outfilename, bool decode_specialized)
{ {
QPDF qpdf; QPDF qpdf;
qpdf.processFile(infilename); qpdf.processFile(infilename);
@ -434,10 +414,8 @@ static void process(char const* infilename, char const* outfilename,
StreamReplacer* replacer = new StreamReplacer(&qpdf); StreamReplacer* replacer = new StreamReplacer(&qpdf);
PointerHolder<QPDFObjectHandle::StreamDataProvider> p(replacer); PointerHolder<QPDFObjectHandle::StreamDataProvider> p(replacer);
for (auto& o: qpdf.getAllObjects()) for (auto& o : qpdf.getAllObjects()) {
{ if (o.isStream()) {
if (o.isStream())
{
// Call registerStream for every stream. Only ones that // Call registerStream for every stream. Only ones that
// registerStream decides to replace will actually be // registerStream decides to replace will actually be
// replaced. // replaced.
@ -446,70 +424,58 @@ static void process(char const* infilename, char const* outfilename,
} }
QPDFWriter w(qpdf, outfilename); QPDFWriter w(qpdf, outfilename);
if (decode_specialized) if (decode_specialized) {
{
w.setDecodeLevel(qpdf_dl_specialized); w.setDecodeLevel(qpdf_dl_specialized);
} }
// For the test suite, use static IDs. // For the test suite, use static IDs.
w.setStaticID(true); // for testing only w.setStaticID(true); // for testing only
w.write(); w.write();
std::cout << whoami << ": new file written to " << outfilename std::cout << whoami << ": new file written to " << outfilename << std::endl;
<< std::endl;
} }
static void usage() static void
usage()
{ {
std::cerr std::cerr << "\n"
<< "\n" << "Usage: " << whoami
<< "Usage: " << whoami << " [--decode-specialized] infile outfile\n" << " [--decode-specialized] infile outfile\n"
<< std::endl; << std::endl;
exit(2); exit(2);
} }
int main(int argc, char* argv[]) int
main(int argc, char* argv[])
{ {
whoami = QUtil::getWhoami(argv[0]); whoami = QUtil::getWhoami(argv[0]);
char const* infilename = 0; char const* infilename = 0;
char const* outfilename = 0; char const* outfilename = 0;
bool decode_specialized = false; bool decode_specialized = false;
for (int i = 1; i < argc; ++i) for (int i = 1; i < argc; ++i) {
{ if (strcmp(argv[i], "--decode-specialized") == 0) {
if (strcmp(argv[i], "--decode-specialized") == 0)
{
decode_specialized = true; decode_specialized = true;
} } else if (!infilename) {
else if (! infilename)
{
infilename = argv[i]; infilename = argv[i];
} } else if (!outfilename) {
else if (! outfilename)
{
outfilename = argv[i]; outfilename = argv[i];
} } else {
else
{
usage(); usage();
} }
} }
if (! (infilename && outfilename)) if (!(infilename && outfilename)) {
{
usage(); usage();
} }
try try {
{
// Register our fictitious filter. This enables QPDFWriter to // Register our fictitious filter. This enables QPDFWriter to
// decode our streams. This is not a real filter, so no real // decode our streams. This is not a real filter, so no real
// PDF reading application would be able to interpret it. This // PDF reading application would be able to interpret it. This
// is just for illustrative purposes. // is just for illustrative purposes.
QPDF::registerStreamFilter( QPDF::registerStreamFilter(
"/XORDecode", []{ return std::make_shared<SF_XORDecode>(); }); "/XORDecode", [] { return std::make_shared<SF_XORDecode>(); });
// Do the actual processing. // Do the actual processing.
process(infilename, outfilename, decode_specialized); process(infilename, outfilename, decode_specialized);
} } catch (std::exception& e) {
catch (std::exception &e)
{
std::cerr << whoami << ": exception: " << e.what() << std::endl; std::cerr << whoami << ": exception: " << e.what() << std::endl;
exit(2); exit(2);
} }

View File

@ -1,16 +1,17 @@
#include <iostream> #include <qpdf/Buffer.hh>
#include <string.h>
#include <stdlib.h>
#include <qpdf/QPDF.hh> #include <qpdf/QPDF.hh>
#include <qpdf/QPDFPageDocumentHelper.hh> #include <qpdf/QPDFPageDocumentHelper.hh>
#include <qpdf/QPDFPageObjectHelper.hh> #include <qpdf/QPDFPageObjectHelper.hh>
#include <qpdf/QUtil.hh>
#include <qpdf/Buffer.hh>
#include <qpdf/QPDFWriter.hh> #include <qpdf/QPDFWriter.hh>
#include <qpdf/QUtil.hh>
#include <iostream>
#include <stdlib.h>
#include <string.h>
static char const* whoami = 0; static char const* whoami = 0;
void usage() void
usage()
{ {
std::cerr << "Usage: " << whoami << " infile.pdf outfile.pdf [in-password]" std::cerr << "Usage: " << whoami << " infile.pdf outfile.pdf [in-password]"
<< std::endl << std::endl
@ -21,45 +22,43 @@ void usage()
// If there is a box of name box_name, replace it with a new box whose // If there is a box of name box_name, replace it with a new box whose
// elements are double the values of the original box. // elements are double the values of the original box.
static void doubleBoxSize(QPDFPageObjectHelper& page, char const* box_name) static void
doubleBoxSize(QPDFPageObjectHelper& page, char const* box_name)
{ {
// We need to use getAttribute rather than getKey as some boxes could // We need to use getAttribute rather than getKey as some boxes could
// be inherited. // be inherited.
auto box = page.getAttribute(box_name, true); auto box = page.getAttribute(box_name, true);
if (box.isNull()) if (box.isNull()) {
{
return; return;
} }
if (! box.isRectangle()) if (!box.isRectangle()) {
{ throw std::runtime_error(
throw std::runtime_error(std::string("box ") + box_name + std::string("box ") + box_name +
" is not an array of four elements"); " is not an array of four elements");
} }
std::vector<QPDFObjectHandle> doubled; std::vector<QPDFObjectHandle> doubled;
for (auto& item : box.aitems()) for (auto& item : box.aitems()) {
{
doubled.push_back( doubled.push_back(
QPDFObjectHandle::newReal(item.getNumericValue() * 2.0, 2)); QPDFObjectHandle::newReal(item.getNumericValue() * 2.0, 2));
} }
page.getObjectHandle() page.getObjectHandle().replaceKey(
.replaceKey(box_name, QPDFObjectHandle::newArray(doubled)); box_name, QPDFObjectHandle::newArray(doubled));
} }
int main(int argc, char* argv[]) int
main(int argc, char* argv[])
{ {
whoami = QUtil::getWhoami(argv[0]); whoami = QUtil::getWhoami(argv[0]);
// For test suite // For test suite
bool static_id = false; bool static_id = false;
if ((argc > 1) && (strcmp(argv[1], " --static-id") == 0)) if ((argc > 1) && (strcmp(argv[1], " --static-id") == 0)) {
{
static_id = true; static_id = true;
--argc; --argc;
++argv; ++argv;
} }
if (! ((argc == 3) || (argc == 4))) if (!((argc == 3) || (argc == 4))) {
{
usage(); usage();
} }
@ -70,13 +69,11 @@ int main(int argc, char* argv[])
// Text to prepend to each page's contents // Text to prepend to each page's contents
std::string content = "2 0 0 2 0 0 cm\n"; std::string content = "2 0 0 2 0 0 cm\n";
try try {
{
QPDF qpdf; QPDF qpdf;
qpdf.processFile(infilename, password); qpdf.processFile(infilename, password);
for (auto& page : QPDFPageDocumentHelper(qpdf).getAllPages()) for (auto& page : QPDFPageDocumentHelper(qpdf).getAllPages()) {
{
// Prepend the buffer to the page's contents // Prepend the buffer to the page's contents
page.addPageContents( page.addPageContents(
QPDFObjectHandle::newStream(&qpdf, content), true); QPDFObjectHandle::newStream(&qpdf, content), true);
@ -91,8 +88,7 @@ int main(int argc, char* argv[])
// Write out a new file // Write out a new file
QPDFWriter w(qpdf, outfilename); QPDFWriter w(qpdf, outfilename);
if (static_id) if (static_id) {
{
// For the test suite, uncompress streams and use static IDs. // For the test suite, uncompress streams and use static IDs.
w.setStaticID(true); // for testing only w.setStaticID(true); // for testing only
w.setStreamDataMode(qpdf_s_uncompress); w.setStreamDataMode(qpdf_s_uncompress);
@ -100,9 +96,7 @@ int main(int argc, char* argv[])
w.write(); w.write();
std::cout << whoami << ": new file written to " << outfilename std::cout << whoami << ": new file written to " << outfilename
<< std::endl; << std::endl;
} } catch (std::exception& e) {
catch (std::exception &e)
{
std::cerr << whoami << " processing file " << infilename << ": " std::cerr << whoami << " processing file " << infilename << ": "
<< e.what() << std::endl; << e.what() << std::endl;
exit(2); exit(2);

View File

@ -5,22 +5,23 @@
// QPDFObjectHandle::TokenFilter with filterContents. // QPDFObjectHandle::TokenFilter with filterContents.
// //
#include <iostream>
#include <string.h>
#include <stdlib.h>
#include <algorithm> #include <algorithm>
#include <deque> #include <deque>
#include <iostream>
#include <stdlib.h>
#include <string.h>
#include <qpdf/QPDF.hh> #include <qpdf/QPDF.hh>
#include <qpdf/QPDFObjectHandle.hh>
#include <qpdf/QPDFPageDocumentHelper.hh> #include <qpdf/QPDFPageDocumentHelper.hh>
#include <qpdf/QPDFPageObjectHelper.hh> #include <qpdf/QPDFPageObjectHelper.hh>
#include <qpdf/QUtil.hh>
#include <qpdf/QPDFWriter.hh> #include <qpdf/QPDFWriter.hh>
#include <qpdf/QPDFObjectHandle.hh> #include <qpdf/QUtil.hh>
static char const* whoami = 0; static char const* whoami = 0;
void usage() void
usage()
{ {
std::cerr << "Usage: " << whoami << " infile outfile" << std::endl std::cerr << "Usage: " << whoami << " infile outfile" << std::endl
<< "Applies token filters to infile and writes outfile" << "Applies token filters to infile and writes outfile"
@ -52,14 +53,11 @@ StringReverser::handleToken(QPDFTokenizer::Token const& token)
// strings. It's just intended to give a simple example of a // strings. It's just intended to give a simple example of a
// pretty minimal filter and to show an example of writing a // pretty minimal filter and to show an example of writing a
// constructed token. // constructed token.
if (token.getType() == QPDFTokenizer::tt_string) if (token.getType() == QPDFTokenizer::tt_string) {
{
std::string value = token.getValue(); std::string value = token.getValue();
std::reverse(value.begin(), value.end()); std::reverse(value.begin(), value.end());
writeToken(QPDFTokenizer::Token(QPDFTokenizer::tt_string, value)); writeToken(QPDFTokenizer::Token(QPDFTokenizer::tt_string, value));
} } else {
else
{
writeToken(token); writeToken(token);
} }
} }
@ -90,15 +88,17 @@ class ColorToGray: public QPDFObjectHandle::TokenFilter
bool bool
ColorToGray::isNumeric(QPDFTokenizer::token_type_e token_type) ColorToGray::isNumeric(QPDFTokenizer::token_type_e token_type)
{ {
return ((token_type == QPDFTokenizer::tt_integer) || return (
(token_type == QPDFTokenizer::tt_real)); (token_type == QPDFTokenizer::tt_integer) ||
(token_type == QPDFTokenizer::tt_real));
} }
bool bool
ColorToGray::isIgnorable(QPDFTokenizer::token_type_e token_type) ColorToGray::isIgnorable(QPDFTokenizer::token_type_e token_type)
{ {
return ((token_type == QPDFTokenizer::tt_space) || return (
(token_type == QPDFTokenizer::tt_comment)); (token_type == QPDFTokenizer::tt_space) ||
(token_type == QPDFTokenizer::tt_comment));
} }
double double
@ -134,33 +134,28 @@ ColorToGray::handleToken(QPDFTokenizer::Token const& token)
// kinds of operands, replace the command. Flush any additional // kinds of operands, replace the command. Flush any additional
// accumulated tokens to keep the stack only four tokens deep. // accumulated tokens to keep the stack only four tokens deep.
while ((! this->all_stack.empty()) && while ((!this->all_stack.empty()) &&
isIgnorable(this->all_stack.at(0).getType())) isIgnorable(this->all_stack.at(0).getType())) {
{
writeToken(this->all_stack.at(0)); writeToken(this->all_stack.at(0));
this->all_stack.pop_front(); this->all_stack.pop_front();
} }
this->all_stack.push_back(token); this->all_stack.push_back(token);
QPDFTokenizer::token_type_e token_type = token.getType(); QPDFTokenizer::token_type_e token_type = token.getType();
if (! isIgnorable(token_type)) if (!isIgnorable(token_type)) {
{
this->stack.push_back(token); this->stack.push_back(token);
if ((this->stack.size() == 4) && if ((this->stack.size() == 4) &&
(token == QPDFTokenizer::Token(QPDFTokenizer::tt_word, "rg")) && (token == QPDFTokenizer::Token(QPDFTokenizer::tt_word, "rg")) &&
(isNumeric(this->stack.at(0).getType())) && (isNumeric(this->stack.at(0).getType())) &&
(isNumeric(this->stack.at(1).getType())) && (isNumeric(this->stack.at(1).getType())) &&
(isNumeric(this->stack.at(2).getType()))) (isNumeric(this->stack.at(2).getType()))) {
{
double r = numericValue(this->stack.at(0)); double r = numericValue(this->stack.at(0));
double g = numericValue(this->stack.at(1)); double g = numericValue(this->stack.at(1));
double b = numericValue(this->stack.at(2)); double b = numericValue(this->stack.at(2));
double gray = ((0.3 * r) + (0.59 * b) + (0.11 * g)); double gray = ((0.3 * r) + (0.59 * b) + (0.11 * g));
if (gray > 1.0) if (gray > 1.0) {
{
gray = 1.0; gray = 1.0;
} }
if (gray < 0.0) if (gray < 0.0) {
{
gray = 0.0; gray = 0.0;
} }
write(QUtil::double_to_string(gray, 3)); write(QUtil::double_to_string(gray, 3));
@ -169,8 +164,7 @@ ColorToGray::handleToken(QPDFTokenizer::Token const& token)
this->all_stack.clear(); this->all_stack.clear();
} }
} }
if (this->stack.size() == 4) if (this->stack.size() == 4) {
{
writeToken(this->all_stack.at(0)); writeToken(this->all_stack.at(0));
this->all_stack.pop_front(); this->all_stack.pop_front();
this->stack.pop_front(); this->stack.pop_front();
@ -181,33 +175,31 @@ void
ColorToGray::handleEOF() ColorToGray::handleEOF()
{ {
// Flush out any remaining accumulated tokens. // Flush out any remaining accumulated tokens.
while (! this->all_stack.empty()) while (!this->all_stack.empty()) {
{
writeToken(this->all_stack.at(0)); writeToken(this->all_stack.at(0));
this->all_stack.pop_front(); this->all_stack.pop_front();
} }
} }
int main(int argc, char* argv[]) int
main(int argc, char* argv[])
{ {
whoami = QUtil::getWhoami(argv[0]); whoami = QUtil::getWhoami(argv[0]);
if (argc != 3) if (argc != 3) {
{
usage(); usage();
} }
char const* infilename = argv[1]; char const* infilename = argv[1];
char const* outfilename = argv[2]; char const* outfilename = argv[2];
try try {
{
QPDF pdf; QPDF pdf;
pdf.processFile(infilename); pdf.processFile(infilename);
std::vector<QPDFPageObjectHelper> pages = std::vector<QPDFPageObjectHelper> pages =
QPDFPageDocumentHelper(pdf).getAllPages(); QPDFPageDocumentHelper(pdf).getAllPages();
for (std::vector<QPDFPageObjectHelper>::iterator iter = pages.begin(); for (std::vector<QPDFPageObjectHelper>::iterator iter = pages.begin();
iter != pages.end(); ++iter) iter != pages.end();
{ ++iter) {
// Attach two token filters to each page of this file. // Attach two token filters to each page of this file.
// When the file is written, or when the pages' contents // When the file is written, or when the pages' contents
// are retrieved in any other way, the filters will be // are retrieved in any other way, the filters will be
@ -222,11 +214,9 @@ int main(int argc, char* argv[])
} }
QPDFWriter w(pdf, outfilename); QPDFWriter w(pdf, outfilename);
w.setStaticID(true); // for testing only w.setStaticID(true); // for testing only
w.write(); w.write();
} } catch (std::exception& e) {
catch (std::exception& e)
{
std::cerr << whoami << ": " << e.what() << std::endl; std::cerr << whoami << ": " << e.what() << std::endl;
exit(2); exit(2);
} }

View File

@ -1,17 +1,18 @@
#include <iostream> #include <qpdf/Buffer.hh>
#include <string.h> #include <qpdf/QIntC.hh>
#include <stdlib.h>
#include <qpdf/QPDF.hh> #include <qpdf/QPDF.hh>
#include <qpdf/QPDFPageDocumentHelper.hh> #include <qpdf/QPDFPageDocumentHelper.hh>
#include <qpdf/QPDFPageObjectHelper.hh> #include <qpdf/QPDFPageObjectHelper.hh>
#include <qpdf/QUtil.hh>
#include <qpdf/Buffer.hh>
#include <qpdf/QPDFWriter.hh> #include <qpdf/QPDFWriter.hh>
#include <qpdf/QIntC.hh> #include <qpdf/QUtil.hh>
#include <iostream>
#include <stdlib.h>
#include <string.h>
static char const* whoami = 0; static char const* whoami = 0;
void usage() void
usage()
{ {
std::cerr << "Usage: " << whoami << " infile.pdf outfile.pdf [in-password]" std::cerr << "Usage: " << whoami << " infile.pdf outfile.pdf [in-password]"
<< std::endl << std::endl
@ -35,8 +36,8 @@ class ImageInverter: public QPDFObjectHandle::StreamDataProvider
virtual ~ImageInverter() virtual ~ImageInverter()
{ {
} }
virtual void provideStreamData(int objid, int generation, virtual void
Pipeline* pipeline) override; provideStreamData(int objid, int generation, Pipeline* pipeline) override;
void registerImage( void registerImage(
QPDFObjectHandle image, QPDFObjectHandle image,
@ -64,8 +65,7 @@ ImageInverter::registerImage(
// generation number. Recall that a single image object may be // generation number. Recall that a single image object may be
// used more than once, so no need to update the same stream // used more than once, so no need to update the same stream
// multiple times. // multiple times.
if (this->copied_images.count(og) > 0) if (this->copied_images.count(og) > 0) {
{
return; return;
} }
this->copied_images[og] = image.copyStream(); this->copied_images[og] = image.copyStream();
@ -79,14 +79,12 @@ ImageInverter::registerImage(
// filterable in the input QPDF object, so we don't have to deal // filterable in the input QPDF object, so we don't have to deal
// with it explicitly here. We could explicitly use /DCTDecode and // with it explicitly here. We could explicitly use /DCTDecode and
// write through a DCT filter if we wanted. // write through a DCT filter if we wanted.
image.replaceStreamData(self, image.replaceStreamData(
QPDFObjectHandle::newNull(), self, QPDFObjectHandle::newNull(), QPDFObjectHandle::newNull());
QPDFObjectHandle::newNull());
} }
void void
ImageInverter::provideStreamData(int objid, int generation, ImageInverter::provideStreamData(int objid, int generation, Pipeline* pipeline)
Pipeline* pipeline)
{ {
// Use the object and generation number supplied to look up the // Use the object and generation number supplied to look up the
// image data. Then invert the image data and write the inverted // image data. Then invert the image data and write the inverted
@ -97,29 +95,27 @@ ImageInverter::provideStreamData(int objid, int generation,
size_t size = data->getSize(); size_t size = data->getSize();
unsigned char* buf = data->getBuffer(); unsigned char* buf = data->getBuffer();
unsigned char ch; unsigned char ch;
for (size_t i = 0; i < size; ++i) for (size_t i = 0; i < size; ++i) {
{
ch = QIntC::to_uchar(0xff - buf[i]); ch = QIntC::to_uchar(0xff - buf[i]);
pipeline->write(&ch, 1); pipeline->write(&ch, 1);
} }
pipeline->finish(); pipeline->finish();
} }
int main(int argc, char* argv[]) int
main(int argc, char* argv[])
{ {
whoami = QUtil::getWhoami(argv[0]); whoami = QUtil::getWhoami(argv[0]);
// For test suite // For test suite
bool static_id = false; bool static_id = false;
if ((argc > 1) && (strcmp(argv[1], " --static-id") == 0)) if ((argc > 1) && (strcmp(argv[1], " --static-id") == 0)) {
{
static_id = true; static_id = true;
--argc; --argc;
++argv; ++argv;
} }
if (! ((argc == 3) || (argc == 4))) if (!((argc == 3) || (argc == 4))) {
{
usage(); usage();
} }
@ -127,8 +123,7 @@ int main(int argc, char* argv[])
char const* outfilename = argv[2]; char const* outfilename = argv[2];
char const* password = (argc == 4) ? argv[3] : ""; char const* password = (argc == 4) ? argv[3] : "";
try try {
{
QPDF qpdf; QPDF qpdf;
qpdf.processFile(infilename, password); qpdf.processFile(infilename, password);
@ -139,18 +134,15 @@ int main(int argc, char* argv[])
std::vector<QPDFPageObjectHelper> pages = std::vector<QPDFPageObjectHelper> pages =
QPDFPageDocumentHelper(qpdf).getAllPages(); QPDFPageDocumentHelper(qpdf).getAllPages();
for (std::vector<QPDFPageObjectHelper>::iterator iter = pages.begin(); for (std::vector<QPDFPageObjectHelper>::iterator iter = pages.begin();
iter != pages.end(); ++iter) iter != pages.end();
{ ++iter) {
QPDFPageObjectHelper& page(*iter); QPDFPageObjectHelper& page(*iter);
// Get all images on the page. // Get all images on the page.
std::map<std::string, QPDFObjectHandle> images = std::map<std::string, QPDFObjectHandle> images = page.getImages();
page.getImages(); for (auto& iter2 : images) {
for (auto& iter2: images)
{
QPDFObjectHandle& image = iter2.second; QPDFObjectHandle& image = iter2.second;
QPDFObjectHandle image_dict = image.getDict(); QPDFObjectHandle image_dict = image.getDict();
QPDFObjectHandle color_space = QPDFObjectHandle color_space = image_dict.getKey("/ColorSpace");
image_dict.getKey("/ColorSpace");
QPDFObjectHandle bits_per_component = QPDFObjectHandle bits_per_component =
image_dict.getKey("/BitsPerComponent"); image_dict.getKey("/BitsPerComponent");
@ -159,12 +151,10 @@ int main(int argc, char* argv[])
// pipeStreamData with a null pipeline to determine // pipeStreamData with a null pipeline to determine
// whether the image is filterable. Directly inspect // whether the image is filterable. Directly inspect
// keys to determine the image type. // keys to determine the image type.
if (image.pipeStreamData(0, qpdf_ef_compress, if (image.pipeStreamData(0, qpdf_ef_compress, qpdf_dl_all) &&
qpdf_dl_all) &&
color_space.isNameAndEquals("/DeviceGray") && color_space.isNameAndEquals("/DeviceGray") &&
bits_per_component.isInteger() && bits_per_component.isInteger() &&
(bits_per_component.getIntValue() == 8)) (bits_per_component.getIntValue() == 8)) {
{
inv->registerImage(image, p); inv->registerImage(image, p);
} }
} }
@ -172,8 +162,7 @@ int main(int argc, char* argv[])
// Write out a new file // Write out a new file
QPDFWriter w(qpdf, outfilename); QPDFWriter w(qpdf, outfilename);
if (static_id) if (static_id) {
{
// For the test suite, uncompress streams and use static // For the test suite, uncompress streams and use static
// IDs. // IDs.
w.setStaticID(true); // for testing only w.setStaticID(true); // for testing only
@ -181,9 +170,7 @@ int main(int argc, char* argv[])
w.write(); w.write();
std::cout << whoami << ": new file written to " << outfilename std::cout << whoami << ": new file written to " << outfilename
<< std::endl; << std::endl;
} } catch (std::exception& e) {
catch (std::exception &e)
{
std::cerr << whoami << " processing file " << infilename << ": " std::cerr << whoami << " processing file " << infilename << ": "
<< e.what() << std::endl; << e.what() << std::endl;
exit(2); exit(2);

View File

@ -9,18 +9,21 @@
static char const* whoami = 0; static char const* whoami = 0;
static void usage() static void
usage()
{ {
fprintf(stderr, "Usage: %s infile infile-password outfile\n", whoami); fprintf(stderr, "Usage: %s infile infile-password outfile\n", whoami);
exit(2); exit(2);
} }
static void write_progress(int percent, void* data) static void
write_progress(int percent, void* data)
{ {
printf("%s progress: %d%%\n", (char const*)(data), percent); printf("%s progress: %d%%\n", (char const*)(data), percent);
} }
int main(int argc, char* argv[]) int
main(int argc, char* argv[])
{ {
char* infile = NULL; char* infile = NULL;
char* password = NULL; char* password = NULL;
@ -30,21 +33,15 @@ int main(int argc, char* argv[])
int errors = 0; int errors = 0;
char* p = 0; char* p = 0;
if ((p = strrchr(argv[0], '/')) != NULL) if ((p = strrchr(argv[0], '/')) != NULL) {
{
whoami = p + 1; whoami = p + 1;
} } else if ((p = strrchr(argv[0], '\\')) != NULL) {
else if ((p = strrchr(argv[0], '\\')) != NULL)
{
whoami = p + 1; whoami = p + 1;
} } else {
else
{
whoami = argv[0]; whoami = argv[0];
} }
if (argc != 4) if (argc != 4) {
{
usage(); usage();
} }
@ -53,8 +50,7 @@ int main(int argc, char* argv[])
outfile = argv[3]; outfile = argv[3];
if (((qpdf_read(qpdf, infile, password) & QPDF_ERRORS) == 0) && if (((qpdf_read(qpdf, infile, password) & QPDF_ERRORS) == 0) &&
((qpdf_init_write(qpdf, outfile) & QPDF_ERRORS) == 0)) ((qpdf_init_write(qpdf, outfile) & QPDF_ERRORS) == 0)) {
{
/* Use static ID for testing only. For production, a /* Use static ID for testing only. For production, a
* non-static ID is used. See also * non-static ID is used. See also
* qpdf_set_deterministic_ID. */ * qpdf_set_deterministic_ID. */
@ -63,25 +59,22 @@ int main(int argc, char* argv[])
qpdf_register_progress_reporter(qpdf, write_progress, infile); qpdf_register_progress_reporter(qpdf, write_progress, infile);
qpdf_write(qpdf); qpdf_write(qpdf);
} }
while (qpdf_more_warnings(qpdf)) while (qpdf_more_warnings(qpdf)) {
{
warnings = 1; warnings = 1;
printf("warning: %s\n", printf(
qpdf_get_error_full_text(qpdf, qpdf_next_warning(qpdf))); "warning: %s\n",
qpdf_get_error_full_text(qpdf, qpdf_next_warning(qpdf)));
} }
if (qpdf_has_error(qpdf)) if (qpdf_has_error(qpdf)) {
{
errors = 1; errors = 1;
printf("error: %s\n", printf(
qpdf_get_error_full_text(qpdf, qpdf_get_error(qpdf))); "error: %s\n",
qpdf_get_error_full_text(qpdf, qpdf_get_error(qpdf)));
} }
qpdf_cleanup(&qpdf); qpdf_cleanup(&qpdf);
if (errors) if (errors) {
{
return 2; return 2;
} } else if (warnings) {
else if (warnings)
{
return 3; return 3;
} }

View File

@ -1,49 +1,43 @@
// Author: Vitaliy Pavlyuk // Author: Vitaliy Pavlyuk
#include <qpdf/QPDF.hh> #include <qpdf/QPDF.hh>
#include <qpdf/QPDFWriter.hh>
#include <qpdf/QPDFObjectHandle.hh> #include <qpdf/QPDFObjectHandle.hh>
#include <qpdf/QUtil.hh> #include <qpdf/QPDFWriter.hh>
#include <qpdf/QTC.hh> #include <qpdf/QTC.hh>
#include <qpdf/QUtil.hh>
#include <iostream> #include <iostream>
#include <string.h>
#include <stdlib.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h>
#include <string.h>
static char const* version = "1.1"; static char const* version = "1.1";
static char const* whoami = 0; static char const* whoami = 0;
void usage() void
usage()
{ {
std::cerr std::cerr << "Usage: " << whoami
<< "Usage: " << whoami << " --in in_file [--out out_file] [--key key [--val val]?]+\n"
<< " --in in_file [--out out_file] [--key key [--val val]?]+\n" << "Modifies/Adds/Removes PDF /Info entries in the in_file\n"
<< "Modifies/Adds/Removes PDF /Info entries in the in_file\n" << "and stores the result in out_file\n"
<< "and stores the result in out_file\n" << "Special mode: " << whoami << " --dump file\n"
<< "Special mode: " << whoami << " --dump file\n" << "dumps all /Info entries to stdout\n";
<< "dumps all /Info entries to stdout\n";
exit(2); exit(2);
} }
void dumpInfoDict(QPDF& pdf, void
std::ostream& os = std::cout, dumpInfoDict(
std::string const& sep = ":\t") QPDF& pdf, std::ostream& os = std::cout, std::string const& sep = ":\t")
{ {
QPDFObjectHandle trailer = pdf.getTrailer(); QPDFObjectHandle trailer = pdf.getTrailer();
if (trailer.hasKey("/Info")) if (trailer.hasKey("/Info")) {
{ for (auto& it : trailer.getKey("/Info").ditems()) {
for (auto& it: trailer.getKey("/Info").ditems())
{
std::string val; std::string val;
if (it.second.isString()) if (it.second.isString()) {
{
val = it.second.getStringValue(); val = it.second.getStringValue();
} } else if (it.second.isName()) {
else if (it.second.isName())
{
val = it.second.getName(); val = it.second.getName();
} } else // according to PDF Spec 1.5, shouldn't happen
else // according to PDF Spec 1.5, shouldn't happen
{ {
val = it.second.unparseResolved(); val = it.second.unparseResolved();
} }
@ -52,36 +46,32 @@ void dumpInfoDict(QPDF& pdf,
} }
} }
void pdfDumpInfoDict(char const* fname) void
pdfDumpInfoDict(char const* fname)
{ {
try try {
{
QPDF pdf; QPDF pdf;
pdf.processFile(fname); pdf.processFile(fname);
dumpInfoDict(pdf); dumpInfoDict(pdf);
} } catch (std::exception& e) {
catch (std::exception& e)
{
std::cerr << e.what() << std::endl; std::cerr << e.what() << std::endl;
exit(2); exit(2);
} }
} }
int main(int argc, char* argv[]) int
main(int argc, char* argv[])
{ {
bool static_id = false; bool static_id = false;
std::map<std::string, std::string> Keys; std::map<std::string, std::string> Keys;
whoami = QUtil::getWhoami(argv[0]); whoami = QUtil::getWhoami(argv[0]);
if ((argc == 2) && (! strcmp(argv[1], "--version")) ) if ((argc == 2) && (!strcmp(argv[1], "--version"))) {
{
std::cout << whoami << " version " << version << std::endl; std::cout << whoami << " version " << version << std::endl;
exit(0); exit(0);
} }
if ((argc == 3) && (! strcmp(argv[1], "--dump"))) if ((argc == 3) && (!strcmp(argv[1], "--dump"))) {
{
QTC::TC("examples", "pdf-mod-info --dump"); QTC::TC("examples", "pdf-mod-info --dump");
pdfDumpInfoDict(argv[2]); pdfDumpInfoDict(argv[2]);
exit(0); exit(0);
@ -91,59 +81,43 @@ int main(int argc, char* argv[])
char* fl_out = 0; char* fl_out = 0;
std::string cur_key; std::string cur_key;
for (int i = 1; i < argc; ++i) for (int i = 1; i < argc; ++i) {
{ if ((!strcmp(argv[i], "--in")) && (++i < argc)) {
if ((! strcmp(argv[i], "--in")) && (++i < argc))
{
fl_in = argv[i]; fl_in = argv[i];
} } else if ((!strcmp(argv[i], "--out")) && (++i < argc)) {
else if ((! strcmp(argv[i], "--out")) && (++i < argc))
{
fl_out = argv[i]; fl_out = argv[i];
} } else if (!strcmp(argv[i], "--static-id")) // don't document
else if (! strcmp(argv[i], "--static-id")) // don't document
{ {
static_id = true; // this should be used in test suites only static_id = true; // this should be used in test suites only
} } else if ((!strcmp(argv[i], "--key")) && (++i < argc)) {
else if ((! strcmp(argv[i], "--key")) && (++i < argc))
{
QTC::TC("examples", "pdf-mod-info -key"); QTC::TC("examples", "pdf-mod-info -key");
cur_key = argv[i]; cur_key = argv[i];
if (! ((cur_key.length() > 0) && (cur_key.at(0) == '/'))) if (!((cur_key.length() > 0) && (cur_key.at(0) == '/'))) {
{
cur_key = "/" + cur_key; cur_key = "/" + cur_key;
} }
Keys[cur_key] = ""; Keys[cur_key] = "";
} } else if ((!strcmp(argv[i], "--val")) && (++i < argc)) {
else if ((! strcmp(argv[i], "--val")) && (++i < argc)) if (cur_key.empty()) {
{
if (cur_key.empty())
{
QTC::TC("examples", "pdf-mod-info usage wrong val"); QTC::TC("examples", "pdf-mod-info usage wrong val");
usage(); usage();
} }
QTC::TC("examples", "pdf-mod-info -val"); QTC::TC("examples", "pdf-mod-info -val");
Keys[cur_key] = argv[i]; Keys[cur_key] = argv[i];
cur_key.clear(); cur_key.clear();
} } else {
else
{
QTC::TC("examples", "pdf-mod-info usage junk"); QTC::TC("examples", "pdf-mod-info usage junk");
usage(); usage();
} }
} }
if (! fl_in) if (!fl_in) {
{
QTC::TC("examples", "pdf-mod-info no in file"); QTC::TC("examples", "pdf-mod-info no in file");
usage(); usage();
} }
if (! fl_out) if (!fl_out) {
{
QTC::TC("examples", "pdf-mod-info in-place"); QTC::TC("examples", "pdf-mod-info in-place");
fl_out = fl_in; fl_out = fl_in;
} }
if (Keys.size() == 0) if (Keys.size() == 0) {
{
QTC::TC("examples", "pdf-mod-info no keys"); QTC::TC("examples", "pdf-mod-info no keys");
usage(); usage();
} }
@ -151,8 +125,7 @@ int main(int argc, char* argv[])
std::string fl_tmp = fl_out; std::string fl_tmp = fl_out;
fl_tmp += ".tmp"; fl_tmp += ".tmp";
try try {
{
QPDF file; QPDF file;
file.processFile(fl_in); file.processFile(fl_in);
@ -160,28 +133,22 @@ int main(int argc, char* argv[])
QPDFObjectHandle fileinfo; QPDFObjectHandle fileinfo;
for (std::map<std::string, std::string>::const_iterator it = for (std::map<std::string, std::string>::const_iterator it =
Keys.begin(); Keys.end() != it; ++it) Keys.begin();
{ Keys.end() != it;
if (! fileinfo.isInitialized()) ++it) {
{ if (!fileinfo.isInitialized()) {
if (filetrailer.hasKey("/Info")) if (filetrailer.hasKey("/Info")) {
{
QTC::TC("examples", "pdf-mod-info has info"); QTC::TC("examples", "pdf-mod-info has info");
fileinfo = filetrailer.getKey("/Info"); fileinfo = filetrailer.getKey("/Info");
} } else {
else
{
QTC::TC("examples", "pdf-mod-info file no info"); QTC::TC("examples", "pdf-mod-info file no info");
fileinfo = QPDFObjectHandle::newDictionary(); fileinfo = QPDFObjectHandle::newDictionary();
filetrailer.replaceKey("/Info", fileinfo); filetrailer.replaceKey("/Info", fileinfo);
} }
} }
if (it->second == "") if (it->second == "") {
{
fileinfo.removeKey(it->first); fileinfo.removeKey(it->first);
} } else {
else
{
QPDFObjectHandle elt = fileinfo.newString(it->second); QPDFObjectHandle elt = fileinfo.newString(it->second);
elt.makeDirect(); elt.makeDirect();
fileinfo.replaceKey(it->first, elt); fileinfo.replaceKey(it->first, elt);
@ -192,21 +159,17 @@ int main(int argc, char* argv[])
w.setLinearization(true); w.setLinearization(true);
w.setStaticID(static_id); // for testing only w.setStaticID(static_id); // for testing only
w.write(); w.write();
} } catch (std::exception& e) {
catch (std::exception& e)
{
std::cerr << e.what() << std::endl; std::cerr << e.what() << std::endl;
exit(2); exit(2);
} }
try try {
{ (void)remove(fl_out);
(void) remove(fl_out); QUtil::os_wrapper(
QUtil::os_wrapper("rename " + fl_tmp + " " + std::string(fl_out), "rename " + fl_tmp + " " + std::string(fl_out),
rename(fl_tmp.c_str(), fl_out)); rename(fl_tmp.c_str(), fl_out));
} } catch (std::exception& e) {
catch (std::exception& e)
{
std::cerr << e.what() << std::endl; std::cerr << e.what() << std::endl;
exit(2); exit(2);
} }

View File

@ -3,26 +3,26 @@
#include <qpdf/QPDFNumberTreeObjectHelper.hh> #include <qpdf/QPDFNumberTreeObjectHelper.hh>
#include <qpdf/QPDFWriter.hh> #include <qpdf/QPDFWriter.hh>
#include <qpdf/QUtil.hh> #include <qpdf/QUtil.hh>
#include <iostream>
#include <cstring> #include <cstring>
#include <iostream>
static char const* whoami = 0; static char const* whoami = 0;
void usage() void
usage()
{ {
std::cerr << "Usage: " << whoami << " outfile.pdf" std::cerr << "Usage: " << whoami << " outfile.pdf" << std::endl
<< std::endl
<< "Create some name/number trees and write to a file" << "Create some name/number trees and write to a file"
<< std::endl; << std::endl;
exit(2); exit(2);
} }
int main(int argc, char* argv[]) int
main(int argc, char* argv[])
{ {
whoami = QUtil::getWhoami(argv[0]); whoami = QUtil::getWhoami(argv[0]);
if (argc != 2) if (argc != 2) {
{
usage(); usage();
} }
@ -62,8 +62,8 @@ int main(int argc, char* argv[])
name_tree.insert("R", QPDFObjectHandle::newUnicodeString("rook")); name_tree.insert("R", QPDFObjectHandle::newUnicodeString("rook"));
name_tree.insert("B", QPDFObjectHandle::newUnicodeString("bishop")); name_tree.insert("B", QPDFObjectHandle::newUnicodeString("bishop"));
name_tree.insert("N", QPDFObjectHandle::newUnicodeString("knight")); name_tree.insert("N", QPDFObjectHandle::newUnicodeString("knight"));
auto iter = name_tree.insert( auto iter =
"P", QPDFObjectHandle::newUnicodeString("pawn")); name_tree.insert("P", QPDFObjectHandle::newUnicodeString("pawn"));
// Look at the iterator // Look at the iterator
std::cout << "just inserted " << iter->first << " -> " std::cout << "just inserted " << iter->first << " -> "
<< iter->second.unparse() << std::endl; << iter->second.unparse() << std::endl;
@ -77,28 +77,24 @@ int main(int argc, char* argv[])
// Use range-for iteration // Use range-for iteration
std::cout << "Name tree items:" << std::endl; std::cout << "Name tree items:" << std::endl;
for (auto i: name_tree) for (auto i : name_tree) {
{ std::cout << " " << i.first << " -> " << i.second.unparse()
std::cout << " " << i.first << " -> " << std::endl;
<< i.second.unparse() << std::endl;
} }
// This is a small tree, so everything will be at the root. We can // This is a small tree, so everything will be at the root. We can
// look at it using dictionary and array iterators. // look at it using dictionary and array iterators.
std::cout << "Keys in name tree object:" << std::endl; std::cout << "Keys in name tree object:" << std::endl;
QPDFObjectHandle names; QPDFObjectHandle names;
for (auto const& i: name_tree_oh.ditems()) for (auto const& i : name_tree_oh.ditems()) {
{
std::cout << i.first << std::endl; std::cout << i.first << std::endl;
if (i.first == "/Names") if (i.first == "/Names") {
{
names = i.second; names = i.second;
} }
} }
// Values in names array: // Values in names array:
std::cout << "Values in names:" << std::endl; std::cout << "Values in names:" << std::endl;
for (auto& i: names.aitems()) for (auto& i : names.aitems()) {
{
std::cout << " " << i.unparse() << std::endl; std::cout << " " << i.unparse() << std::endl;
} }
@ -112,8 +108,8 @@ int main(int argc, char* argv[])
// 10.2 API // 10.2 API
iter = name_tree.find("Q"); iter = name_tree.find("Q");
std::cout << "Q: " << iter->first << " -> " std::cout << "Q: " << iter->first << " -> " << iter->second.unparse()
<< iter->second.unparse() << std::endl; << std::endl;
iter = name_tree.find("W"); iter = name_tree.find("W");
std::cout << "W found: " << (iter != name_tree.end()) << std::endl; std::cout << "W found: " << (iter != name_tree.end()) << std::endl;
// Allow find to return predecessor // Allow find to return predecessor
@ -146,22 +142,18 @@ int main(int argc, char* argv[])
auto number_tree_oh = number_tree.getObjectHandle(); auto number_tree_oh = number_tree.getObjectHandle();
example.replaceKey("/NumberTree", number_tree_oh); example.replaceKey("/NumberTree", number_tree_oh);
auto iter2 = number_tree.begin(); auto iter2 = number_tree.begin();
for (int i = 7; i <= 350; i += 7) for (int i = 7; i <= 350; i += 7) {
{ iter2.insertAfter(
iter2.insertAfter(i, QPDFObjectHandle::newString( i,
"-" + QUtil::int_to_string(i) + "-")); QPDFObjectHandle::newString("-" + QUtil::int_to_string(i) + "-"));
} }
std::cout << "Numbers:" << std::endl; std::cout << "Numbers:" << std::endl;
int n = 1; int n = 1;
for (auto& i: number_tree) for (auto& i : number_tree) {
{
std::cout << i.first << " -> " << i.second.getUTF8Value(); std::cout << i.first << " -> " << i.second.getUTF8Value();
if (n % 5) if (n % 5) {
{
std::cout << ", "; std::cout << ", ";
} } else {
else
{
std::cout << std::endl; std::cout << std::endl;
} }
++n; ++n;
@ -171,28 +163,20 @@ int main(int argc, char* argv[])
// advances. This makes it possible to filter while iterating. // advances. This makes it possible to filter while iterating.
// Remove all items that are multiples of 5. // Remove all items that are multiples of 5.
iter2 = number_tree.begin(); iter2 = number_tree.begin();
while (iter2 != number_tree.end()) while (iter2 != number_tree.end()) {
{ if (iter2->first % 5 == 0) {
if (iter2->first % 5 == 0) iter2.remove(); // also advances
{ } else {
iter2.remove(); // also advances
}
else
{
++iter2; ++iter2;
} }
} }
std::cout << "Numbers after filtering:" << std::endl; std::cout << "Numbers after filtering:" << std::endl;
n = 1; n = 1;
for (auto& i: number_tree) for (auto& i : number_tree) {
{
std::cout << i.first << " -> " << i.second.getUTF8Value(); std::cout << i.first << " -> " << i.second.getUTF8Value();
if (n % 5) if (n % 5) {
{
std::cout << ", "; std::cout << ", ";
} } else {
else
{
std::cout << std::endl; std::cout << std::endl;
} }
++n; ++n;

View File

@ -1,46 +1,43 @@
#include <iostream> #include <iostream>
#include <string.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h>
#include <qpdf/QPDF.hh> #include <qpdf/QPDF.hh>
#include <qpdf/QUtil.hh> #include <qpdf/QUtil.hh>
static char const* whoami = 0; static char const* whoami = 0;
void usage() void
usage()
{ {
std::cerr << "Usage: " << whoami << " filename" << std::endl std::cerr << "Usage: " << whoami << " filename" << std::endl
<< "Prints the number of pages in filename" << std::endl; << "Prints the number of pages in filename" << std::endl;
exit(2); exit(2);
} }
int main(int argc, char* argv[]) int
main(int argc, char* argv[])
{ {
whoami = QUtil::getWhoami(argv[0]); whoami = QUtil::getWhoami(argv[0]);
if ((argc == 2) && (strcmp(argv[1], "--version") == 0)) if ((argc == 2) && (strcmp(argv[1], "--version") == 0)) {
{
std::cout << whoami << " version 1.3" << std::endl; std::cout << whoami << " version 1.3" << std::endl;
exit(0); exit(0);
} }
if (argc != 2) if (argc != 2) {
{
usage(); usage();
} }
char const* filename = argv[1]; char const* filename = argv[1];
try try {
{
QPDF pdf; QPDF pdf;
pdf.processFile(filename); pdf.processFile(filename);
QPDFObjectHandle root = pdf.getRoot(); QPDFObjectHandle root = pdf.getRoot();
QPDFObjectHandle pages = root.getKey("/Pages"); QPDFObjectHandle pages = root.getKey("/Pages");
QPDFObjectHandle count = pages.getKey("/Count"); QPDFObjectHandle count = pages.getKey("/Count");
std::cout << count.getIntValue() << std::endl; std::cout << count.getIntValue() << std::endl;
} } catch (std::exception& e) {
catch (std::exception& e)
{
std::cerr << whoami << ": " << e.what() << std::endl; std::cerr << whoami << ": " << e.what() << std::endl;
exit(2); exit(2);
} }

View File

@ -1,11 +1,11 @@
#include <iostream>
#include <string.h>
#include <stdlib.h>
#include <qpdf/QPDF.hh> #include <qpdf/QPDF.hh>
#include <qpdf/QPDFPageDocumentHelper.hh> #include <qpdf/QPDFPageDocumentHelper.hh>
#include <qpdf/QPDFPageObjectHelper.hh> #include <qpdf/QPDFPageObjectHelper.hh>
#include <qpdf/QPDFWriter.hh> #include <qpdf/QPDFWriter.hh>
#include <qpdf/QUtil.hh> #include <qpdf/QUtil.hh>
#include <iostream>
#include <stdlib.h>
#include <string.h>
// This program demonstrates use of form XObjects to overlay a page // This program demonstrates use of form XObjects to overlay a page
// from one file onto all pages of another file. The qpdf program's // from one file onto all pages of another file. The qpdf program's
@ -14,19 +14,17 @@
static char const* whoami = 0; static char const* whoami = 0;
void usage() void
usage()
{ {
std::cerr << "Usage: " << whoami << " infile pagefile outfile" std::cerr << "Usage: " << whoami << " infile pagefile outfile" << std::endl
<< std::endl
<< "Stamp page 1 of pagefile on every page of infile," << "Stamp page 1 of pagefile on every page of infile,"
<< " writing to outfile" << " writing to outfile" << std::endl;
<< std::endl;
exit(2); exit(2);
} }
static void stamp_page(char const* infile, static void
char const* stampfile, stamp_page(char const* infile, char const* stampfile, char const* outfile)
char const* outfile)
{ {
QPDF inpdf; QPDF inpdf;
inpdf.processFile(infile); inpdf.processFile(infile);
@ -45,8 +43,8 @@ static void stamp_page(char const* infile,
std::vector<QPDFPageObjectHelper> pages = std::vector<QPDFPageObjectHelper> pages =
QPDFPageDocumentHelper(inpdf).getAllPages(); QPDFPageDocumentHelper(inpdf).getAllPages();
for (std::vector<QPDFPageObjectHelper>::iterator iter = pages.begin(); for (std::vector<QPDFPageObjectHelper>::iterator iter = pages.begin();
iter != pages.end(); ++iter) iter != pages.end();
{ ++iter) {
QPDFPageObjectHelper& ph = *iter; QPDFPageObjectHelper& ph = *iter;
// Find a unique resource name for the new form XObject // Find a unique resource name for the new form XObject
@ -57,11 +55,9 @@ static void stamp_page(char const* infile,
// Generate content to place the form XObject centered within // Generate content to place the form XObject centered within
// destination page's trim box. // destination page's trim box.
QPDFMatrix m; QPDFMatrix m;
std::string content = std::string content = ph.placeFormXObject(
ph.placeFormXObject( stamp_fo, name, ph.getTrimBox().getArrayAsRectangle(), m);
stamp_fo, name, ph.getTrimBox().getArrayAsRectangle(), m); if (!content.empty()) {
if (! content.empty())
{
// Append the content to the page's content. Surround the // Append the content to the page's content. Surround the
// original content with q...Q to the new content from the // original content with q...Q to the new content from the
// page's original content. // page's original content.
@ -80,28 +76,25 @@ static void stamp_page(char const* infile,
} }
QPDFWriter w(inpdf, outfile); QPDFWriter w(inpdf, outfile);
w.setStaticID(true); // for testing only w.setStaticID(true); // for testing only
w.write(); w.write();
} }
int main(int argc, char* argv[]) int
main(int argc, char* argv[])
{ {
whoami = QUtil::getWhoami(argv[0]); whoami = QUtil::getWhoami(argv[0]);
if (argc != 4) if (argc != 4) {
{
usage(); usage();
} }
char const* infile = argv[1]; char const* infile = argv[1];
char const* stampfile = argv[2]; char const* stampfile = argv[2];
char const* outfile = argv[3]; char const* outfile = argv[3];
try try {
{
stamp_page(infile, stampfile, outfile); stamp_page(infile, stampfile, outfile);
} } catch (std::exception& e) {
catch (std::exception &e)
{
std::cerr << whoami << ": " << e.what() << std::endl; std::cerr << whoami << ": " << e.what() << std::endl;
exit(2); exit(2);
} }

View File

@ -1,16 +1,17 @@
#include <iostream> #include <iostream>
#include <string.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h>
#include <qpdf/QIntC.hh>
#include <qpdf/QPDF.hh> #include <qpdf/QPDF.hh>
#include <qpdf/QPDFPageDocumentHelper.hh> #include <qpdf/QPDFPageDocumentHelper.hh>
#include <qpdf/QPDFPageObjectHelper.hh> #include <qpdf/QPDFPageObjectHelper.hh>
#include <qpdf/QUtil.hh> #include <qpdf/QUtil.hh>
#include <qpdf/QIntC.hh>
static char const* whoami = 0; static char const* whoami = 0;
void usage() void
usage()
{ {
std::cerr << "Usage: " << whoami << " filename page-number" << std::endl std::cerr << "Usage: " << whoami << " filename page-number" << std::endl
<< "Prints a dump of the objects in the content streams" << "Prints a dump of the objects in the content streams"
@ -38,17 +39,14 @@ ParserCallbacks::contentSize(size_t size)
} }
void void
ParserCallbacks::handleObject(QPDFObjectHandle obj, ParserCallbacks::handleObject(
size_t offset, size_t length) QPDFObjectHandle obj, size_t offset, size_t length)
{ {
std::cout << obj.getTypeName() << ", offset=" << offset std::cout << obj.getTypeName() << ", offset=" << offset
<< ", length=" << length << ": "; << ", length=" << length << ": ";
if (obj.isInlineImage()) if (obj.isInlineImage()) {
{
std::cout << QUtil::hex_encode(obj.getInlineImageValue()) << std::endl; std::cout << QUtil::hex_encode(obj.getInlineImageValue()) << std::endl;
} } else {
else
{
std::cout << obj.unparse() << std::endl; std::cout << obj.unparse() << std::endl;
} }
} }
@ -59,34 +57,30 @@ ParserCallbacks::handleEOF()
std::cout << "-EOF-" << std::endl; std::cout << "-EOF-" << std::endl;
} }
int main(int argc, char* argv[]) int
main(int argc, char* argv[])
{ {
whoami = QUtil::getWhoami(argv[0]); whoami = QUtil::getWhoami(argv[0]);
if (argc != 3) if (argc != 3) {
{
usage(); usage();
} }
char const* filename = argv[1]; char const* filename = argv[1];
int pageno = QUtil::string_to_int(argv[2]); int pageno = QUtil::string_to_int(argv[2]);
try try {
{
QPDF pdf; QPDF pdf;
pdf.processFile(filename); pdf.processFile(filename);
std::vector<QPDFPageObjectHelper> pages = std::vector<QPDFPageObjectHelper> pages =
QPDFPageDocumentHelper(pdf).getAllPages(); QPDFPageDocumentHelper(pdf).getAllPages();
if ((pageno < 1) || (QIntC::to_size(pageno) > pages.size())) if ((pageno < 1) || (QIntC::to_size(pageno) > pages.size())) {
{
usage(); usage();
} }
QPDFPageObjectHelper& page = pages.at(QIntC::to_size(pageno-1)); QPDFPageObjectHelper& page = pages.at(QIntC::to_size(pageno - 1));
ParserCallbacks cb; ParserCallbacks cb;
page.parseContents(&cb); page.parseContents(&cb);
} } catch (std::exception& e) {
catch (std::exception& e)
{
std::cerr << whoami << ": " << e.what() << std::endl; std::cerr << whoami << ": " << e.what() << std::endl;
exit(2); exit(2);
} }

View File

@ -1,16 +1,17 @@
#include <stdio.h>
#include <string.h>
#include <iostream>
#include <stdlib.h>
#include <qpdf/QPDF.hh> #include <qpdf/QPDF.hh>
#include <qpdf/QPDFPageDocumentHelper.hh>
#include <qpdf/QPDFAcroFormDocumentHelper.hh> #include <qpdf/QPDFAcroFormDocumentHelper.hh>
#include <qpdf/QPDFPageDocumentHelper.hh>
#include <qpdf/QPDFWriter.hh> #include <qpdf/QPDFWriter.hh>
#include <qpdf/QUtil.hh> #include <qpdf/QUtil.hh>
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
static char const* whoami = 0; static char const* whoami = 0;
void usage() void
usage()
{ {
std::cerr << "Usage: " << whoami << " infile.pdf outfile.pdf value" std::cerr << "Usage: " << whoami << " infile.pdf outfile.pdf value"
<< std::endl << std::endl
@ -19,13 +20,12 @@ void usage()
exit(2); exit(2);
} }
int
int main(int argc, char* argv[]) main(int argc, char* argv[])
{ {
whoami = QUtil::getWhoami(argv[0]); whoami = QUtil::getWhoami(argv[0]);
if (argc != 4) if (argc != 4) {
{
usage(); usage();
} }
@ -39,8 +39,7 @@ int main(int argc, char* argv[])
// to illustrate use of the helper classes around interactive // to illustrate use of the helper classes around interactive
// forms. // forms.
try try {
{
QPDF qpdf; QPDF qpdf;
qpdf.processFile(infilename); qpdf.processFile(infilename);
@ -55,8 +54,8 @@ int main(int argc, char* argv[])
std::vector<QPDFPageObjectHelper> pages = pdh.getAllPages(); std::vector<QPDFPageObjectHelper> pages = pdh.getAllPages();
for (std::vector<QPDFPageObjectHelper>::iterator page_iter = for (std::vector<QPDFPageObjectHelper>::iterator page_iter =
pages.begin(); pages.begin();
page_iter != pages.end(); ++page_iter) page_iter != pages.end();
{ ++page_iter) {
// Get all widget annotations for each page. Widget // Get all widget annotations for each page. Widget
// annotations are the ones that contain the details of // annotations are the ones that contain the details of
// what's in a form field. // what's in a form field.
@ -64,14 +63,13 @@ int main(int argc, char* argv[])
afdh.getWidgetAnnotationsForPage(*page_iter); afdh.getWidgetAnnotationsForPage(*page_iter);
for (std::vector<QPDFAnnotationObjectHelper>::iterator annot_iter = for (std::vector<QPDFAnnotationObjectHelper>::iterator annot_iter =
annotations.begin(); annotations.begin();
annot_iter != annotations.end(); ++annot_iter) annot_iter != annotations.end();
{ ++annot_iter) {
// For each annotation, find its associated field. If // For each annotation, find its associated field. If
// it's a text field, set its value. // it's a text field, set its value.
QPDFFormFieldObjectHelper ffh = QPDFFormFieldObjectHelper ffh =
afdh.getFieldForAnnotation(*annot_iter); afdh.getFieldForAnnotation(*annot_iter);
if (ffh.getFieldType() == "/Tx") if (ffh.getFieldType() == "/Tx") {
{
// Set the value. Passing false as the second // Set the value. Passing false as the second
// value prevents qpdf from setting // value prevents qpdf from setting
// /NeedAppearances to true (but will not turn it // /NeedAppearances to true (but will not turn it
@ -92,9 +90,7 @@ int main(int argc, char* argv[])
QPDFWriter w(qpdf, outfilename); QPDFWriter w(qpdf, outfilename);
w.setStaticID(true); // for testing only w.setStaticID(true); // for testing only
w.write(); w.write();
} } catch (std::exception& e) {
catch (std::exception &e)
{
std::cerr << whoami << " processing file " << infilename << ": " std::cerr << whoami << " processing file " << infilename << ": "
<< e.what() << std::endl; << e.what() << std::endl;
exit(2); exit(2);

View File

@ -4,22 +4,21 @@
// does. // does.
// //
#include <qpdf/QIntC.hh>
#include <qpdf/QPDF.hh> #include <qpdf/QPDF.hh>
#include <qpdf/QPDFPageDocumentHelper.hh> #include <qpdf/QPDFPageDocumentHelper.hh>
#include <qpdf/QPDFWriter.hh> #include <qpdf/QPDFWriter.hh>
#include <qpdf/QUtil.hh> #include <qpdf/QUtil.hh>
#include <qpdf/QIntC.hh>
#include <cstring>
#include <iostream> #include <iostream>
#include <stdlib.h> #include <stdlib.h>
#include <string> #include <string>
#include <cstring>
static bool static_id = false; static bool static_id = false;
static void process(char const* whoami, static void
char const* infile, process(char const* whoami, char const* infile, std::string outprefix)
std::string outprefix)
{ {
QPDF inpdf; QPDF inpdf;
inpdf.processFile(infile); inpdf.processFile(infile);
@ -29,8 +28,8 @@ static void process(char const* whoami,
QIntC::to_int(QUtil::uint_to_string(pages.size()).length()); QIntC::to_int(QUtil::uint_to_string(pages.size()).length());
int pageno = 0; int pageno = 0;
for (std::vector<QPDFPageObjectHelper>::iterator iter = pages.begin(); for (std::vector<QPDFPageObjectHelper>::iterator iter = pages.begin();
iter != pages.end(); ++iter) iter != pages.end();
{ ++iter) {
QPDFPageObjectHelper& page(*iter); QPDFPageObjectHelper& page(*iter);
std::string outfile = std::string outfile =
outprefix + QUtil::int_to_string(++pageno, pageno_len) + ".pdf"; outprefix + QUtil::int_to_string(++pageno, pageno_len) + ".pdf";
@ -38,8 +37,7 @@ static void process(char const* whoami,
outpdf.emptyPDF(); outpdf.emptyPDF();
QPDFPageDocumentHelper(outpdf).addPage(page, false); QPDFPageDocumentHelper(outpdf).addPage(page, false);
QPDFWriter outpdfw(outpdf, outfile.c_str()); QPDFWriter outpdfw(outpdf, outfile.c_str());
if (static_id) if (static_id) {
{
// For the test suite, uncompress streams and use static // For the test suite, uncompress streams and use static
// IDs. // IDs.
outpdfw.setStaticID(true); // for testing only outpdfw.setStaticID(true); // for testing only
@ -49,34 +47,31 @@ static void process(char const* whoami,
} }
} }
void usage(char const* whoami) void
usage(char const* whoami)
{ {
std::cerr << "Usage: " << whoami << " infile outprefix" << std::endl; std::cerr << "Usage: " << whoami << " infile outprefix" << std::endl;
exit(2); exit(2);
} }
int main(int argc, char* argv[]) int
main(int argc, char* argv[])
{ {
char const* whoami = QUtil::getWhoami(argv[0]); char const* whoami = QUtil::getWhoami(argv[0]);
// For test suite // For test suite
if ((argc > 1) && (strcmp(argv[1], " --static-id") == 0)) if ((argc > 1) && (strcmp(argv[1], " --static-id") == 0)) {
{
static_id = true; static_id = true;
--argc; --argc;
++argv; ++argv;
} }
if (argc != 3) if (argc != 3) {
{
usage(whoami); usage(whoami);
} }
try try {
{
process(whoami, argv[1], argv[2]); process(whoami, argv[1], argv[2]);
} } catch (std::exception const& e) {
catch (std::exception const& e)
{
std::cerr << whoami << ": exception: " << e.what() << std::endl; std::cerr << whoami << ": exception: " << e.what() << std::endl;
return 2; return 2;
} }

View File

@ -1,34 +1,32 @@
#include <qpdf/QIntC.hh>
#include <qpdf/QPDFJob.hh> #include <qpdf/QPDFJob.hh>
#include <qpdf/QUtil.hh> #include <qpdf/QUtil.hh>
#include <qpdf/QIntC.hh>
#include <iostream>
#include <cstring> #include <cstring>
#include <iostream>
// This program is a simple demonstration of different ways to use the // This program is a simple demonstration of different ways to use the
// QPDFJob API. // QPDFJob API.
static char const* whoami = 0; static char const* whoami = 0;
static void usage() static void
usage()
{ {
std::cerr std::cerr << "Usage: " << whoami << std::endl
<< "Usage: " << whoami << std::endl << "This program linearizes the first page of in.pdf to out1.pdf,"
<< "This program linearizes the first page of in.pdf to out1.pdf," << " out2.pdf, and" << std::endl
<< " out2.pdf, and" << " out3.pdf, each demonstrating a different way to use the"
<< std::endl << " QPDFJob API" << std::endl;
<< " out3.pdf, each demonstrating a different way to use the"
<< " QPDFJob API"
<< std::endl;
exit(2); exit(2);
} }
int main(int argc, char* argv[]) int
main(int argc, char* argv[])
{ {
whoami = QUtil::getWhoami(argv[0]); whoami = QUtil::getWhoami(argv[0]);
if (argc != 1) if (argc != 1) {
{
usage(); usage();
} }
@ -39,8 +37,7 @@ int main(int argc, char* argv[])
// Note that staticId is used for testing only. // Note that staticId is used for testing only.
try try {
{
// Use the config API // Use the config API
QPDFJob j; QPDFJob j;
j.config() j.config()
@ -54,15 +51,12 @@ int main(int argc, char* argv[])
->checkConfiguration(); ->checkConfiguration();
j.run(); j.run();
std::cout << "out1 status: " << j.getExitCode() << std::endl; std::cout << "out1 status: " << j.getExitCode() << std::endl;
} } catch (std::exception& e) {
catch (std::exception& e)
{
std::cerr << "exception: " << e.what() << std::endl; std::cerr << "exception: " << e.what() << std::endl;
return 2; return 2;
} }
try try {
{
char const* new_argv[] = { char const* new_argv[] = {
whoami, whoami,
"in.pdf", "in.pdf",
@ -73,21 +67,17 @@ int main(int argc, char* argv[])
"1", "1",
"--", "--",
"--static-id", "--static-id",
nullptr nullptr};
};
QPDFJob j; QPDFJob j;
j.initializeFromArgv(new_argv); j.initializeFromArgv(new_argv);
j.run(); j.run();
std::cout << "out2 status: " << j.getExitCode() << std::endl; std::cout << "out2 status: " << j.getExitCode() << std::endl;
} } catch (std::exception& e) {
catch (std::exception& e)
{
std::cerr << "exception: " << e.what() << std::endl; std::cerr << "exception: " << e.what() << std::endl;
return 2; return 2;
} }
try try {
{
// Use the JSON API // Use the JSON API
QPDFJob j; QPDFJob j;
j.initializeFromJson(R"({ j.initializeFromJson(R"({
@ -105,9 +95,7 @@ int main(int argc, char* argv[])
)"); )");
j.run(); j.run();
std::cout << "out3 status: " << j.getExitCode() << std::endl; std::cout << "out3 status: " << j.getExitCode() << std::endl;
} } catch (std::exception& e) {
catch (std::exception& e)
{
std::cerr << "exception: " << e.what() << std::endl; std::cerr << "exception: " << e.what() << std::endl;
return 2; return 2;
} }

View File

@ -10,13 +10,15 @@
static char const* whoami = 0; static char const* whoami = 0;
static void usage() static void
usage()
{ {
fprintf(stderr, "Usage: %s infile outfile\n", whoami); fprintf(stderr, "Usage: %s infile outfile\n", whoami);
exit(2); exit(2);
} }
int main(int argc, char* argv[]) int
main(int argc, char* argv[])
{ {
char* infile = NULL; char* infile = NULL;
char* outfile = NULL; char* outfile = NULL;
@ -24,21 +26,15 @@ int main(int argc, char* argv[])
int r = 0; int r = 0;
char* p = 0; char* p = 0;
if ((p = strrchr(argv[0], '/')) != NULL) if ((p = strrchr(argv[0], '/')) != NULL) {
{
whoami = p + 1; whoami = p + 1;
} } else if ((p = strrchr(argv[0], '\\')) != NULL) {
else if ((p = strrchr(argv[0], '\\')) != NULL)
{
whoami = p + 1; whoami = p + 1;
} } else {
else
{
whoami = argv[0]; whoami = argv[0];
} }
if (argc != 3) if (argc != 3) {
{
usage(); usage();
} }

View File

@ -1,5 +1,5 @@
#include <qpdf/Pl_Discard.hh>
#include <qpdf/Pl_ASCII85Decoder.hh> #include <qpdf/Pl_ASCII85Decoder.hh>
#include <qpdf/Pl_Discard.hh>
#include <iostream> #include <iostream>
#include <stdexcept> #include <stdexcept>
@ -34,17 +34,15 @@ FuzzHelper::doChecks()
void void
FuzzHelper::run() FuzzHelper::run()
{ {
try try {
{
doChecks(); doChecks();
} } catch (std::runtime_error const& e) {
catch (std::runtime_error const& e)
{
std::cerr << "runtime_error: " << e.what() << std::endl; std::cerr << "runtime_error: " << e.what() << std::endl;
} }
} }
extern "C" int LLVMFuzzerTestOneInput(unsigned char const* data, size_t size) extern "C" int
LLVMFuzzerTestOneInput(unsigned char const* data, size_t size)
{ {
FuzzHelper f(data, size); FuzzHelper f(data, size);
f.run(); f.run();

View File

@ -1,8 +1,8 @@
#include <qpdf/Pl_Discard.hh>
#include <qpdf/Pl_DCT.hh> #include <qpdf/Pl_DCT.hh>
#include <qpdf/Pl_Discard.hh>
#include <cstdlib>
#include <iostream> #include <iostream>
#include <stdexcept> #include <stdexcept>
#include <cstdlib>
class FuzzHelper class FuzzHelper
{ {
@ -35,17 +35,15 @@ FuzzHelper::doChecks()
void void
FuzzHelper::run() FuzzHelper::run()
{ {
try try {
{
doChecks(); doChecks();
} } catch (std::runtime_error const& e) {
catch (std::runtime_error const& e)
{
std::cerr << "runtime_error: " << e.what() << std::endl; std::cerr << "runtime_error: " << e.what() << std::endl;
} }
} }
extern "C" int LLVMFuzzerTestOneInput(unsigned char const* data, size_t size) extern "C" int
LLVMFuzzerTestOneInput(unsigned char const* data, size_t size)
{ {
#ifndef _WIN32 #ifndef _WIN32
// Used by jpeg library to work around false positives in memory // Used by jpeg library to work around false positives in memory

View File

@ -34,17 +34,15 @@ FuzzHelper::doChecks()
void void
FuzzHelper::run() FuzzHelper::run()
{ {
try try {
{
doChecks(); doChecks();
} } catch (std::runtime_error const& e) {
catch (std::runtime_error const& e)
{
std::cerr << "runtime_error: " << e.what() << std::endl; std::cerr << "runtime_error: " << e.what() << std::endl;
} }
} }
extern "C" int LLVMFuzzerTestOneInput(unsigned char const* data, size_t size) extern "C" int
LLVMFuzzerTestOneInput(unsigned char const* data, size_t size)
{ {
FuzzHelper f(data, size); FuzzHelper f(data, size);
f.run(); f.run();

View File

@ -1,5 +1,5 @@
#include <qpdf/Pl_Discard.hh>
#include <qpdf/Pl_ASCIIHexDecoder.hh> #include <qpdf/Pl_ASCIIHexDecoder.hh>
#include <qpdf/Pl_Discard.hh>
#include <iostream> #include <iostream>
#include <stdexcept> #include <stdexcept>
@ -34,17 +34,15 @@ FuzzHelper::doChecks()
void void
FuzzHelper::run() FuzzHelper::run()
{ {
try try {
{
doChecks(); doChecks();
} } catch (std::runtime_error const& e) {
catch (std::runtime_error const& e)
{
std::cerr << "runtime_error: " << e.what() << std::endl; std::cerr << "runtime_error: " << e.what() << std::endl;
} }
} }
extern "C" int LLVMFuzzerTestOneInput(unsigned char const* data, size_t size) extern "C" int
LLVMFuzzerTestOneInput(unsigned char const* data, size_t size)
{ {
FuzzHelper f(data, size); FuzzHelper f(data, size);
f.run(); f.run();

View File

@ -34,17 +34,15 @@ FuzzHelper::doChecks()
void void
FuzzHelper::run() FuzzHelper::run()
{ {
try try {
{
doChecks(); doChecks();
} } catch (std::runtime_error const& e) {
catch (std::runtime_error const& e)
{
std::cerr << "runtime_error: " << e.what() << std::endl; std::cerr << "runtime_error: " << e.what() << std::endl;
} }
} }
extern "C" int LLVMFuzzerTestOneInput(unsigned char const* data, size_t size) extern "C" int
LLVMFuzzerTestOneInput(unsigned char const* data, size_t size)
{ {
FuzzHelper f(data, size); FuzzHelper f(data, size);
f.run(); f.run();

View File

@ -34,17 +34,15 @@ FuzzHelper::doChecks()
void void
FuzzHelper::run() FuzzHelper::run()
{ {
try try {
{
doChecks(); doChecks();
} } catch (std::runtime_error const& e) {
catch (std::runtime_error const& e)
{
std::cerr << "runtime_error: " << e.what() << std::endl; std::cerr << "runtime_error: " << e.what() << std::endl;
} }
} }
extern "C" int LLVMFuzzerTestOneInput(unsigned char const* data, size_t size) extern "C" int
LLVMFuzzerTestOneInput(unsigned char const* data, size_t size)
{ {
FuzzHelper f(data, size); FuzzHelper f(data, size);
f.run(); f.run();

View File

@ -1,22 +1,30 @@
#include <qpdf/Buffer.hh>
#include <qpdf/BufferInputSource.hh>
#include <qpdf/Pl_Discard.hh>
#include <qpdf/QPDF.hh> #include <qpdf/QPDF.hh>
#include <qpdf/QPDFAcroFormDocumentHelper.hh>
#include <qpdf/QPDFOutlineDocumentHelper.hh>
#include <qpdf/QPDFPageDocumentHelper.hh>
#include <qpdf/QPDFPageLabelDocumentHelper.hh>
#include <qpdf/QPDFPageObjectHelper.hh>
#include <qpdf/QPDFWriter.hh> #include <qpdf/QPDFWriter.hh>
#include <qpdf/QUtil.hh> #include <qpdf/QUtil.hh>
#include <qpdf/BufferInputSource.hh>
#include <qpdf/Buffer.hh>
#include <qpdf/Pl_Discard.hh>
#include <qpdf/QPDFPageDocumentHelper.hh>
#include <qpdf/QPDFPageObjectHelper.hh>
#include <qpdf/QPDFPageLabelDocumentHelper.hh>
#include <qpdf/QPDFOutlineDocumentHelper.hh>
#include <qpdf/QPDFAcroFormDocumentHelper.hh>
#include <cstdlib> #include <cstdlib>
class DiscardContents: public QPDFObjectHandle::ParserCallbacks class DiscardContents: public QPDFObjectHandle::ParserCallbacks
{ {
public: public:
virtual ~DiscardContents() {} virtual ~DiscardContents()
virtual void handleObject(QPDFObjectHandle) {} {
virtual void handleEOF() {} }
virtual void
handleObject(QPDFObjectHandle)
{
}
virtual void
handleEOF()
{
}
}; };
class FuzzHelper class FuzzHelper
@ -66,16 +74,11 @@ FuzzHelper::getWriter(PointerHolder<QPDF> qpdf)
void void
FuzzHelper::doWrite(PointerHolder<QPDFWriter> w) FuzzHelper::doWrite(PointerHolder<QPDFWriter> w)
{ {
try try {
{
w->write(); w->write();
} } catch (QPDFExc const& e) {
catch (QPDFExc const& e)
{
std::cerr << e.what() << std::endl; std::cerr << e.what() << std::endl;
} } catch (std::runtime_error const& e) {
catch (std::runtime_error const& e)
{
std::cerr << e.what() << std::endl; std::cerr << e.what() << std::endl;
} }
} }
@ -133,14 +136,12 @@ FuzzHelper::testPages()
std::vector<QPDFPageObjectHelper> pages = pdh.getAllPages(); std::vector<QPDFPageObjectHelper> pages = pdh.getAllPages();
DiscardContents discard_contents; DiscardContents discard_contents;
int pageno = 0; int pageno = 0;
for (std::vector<QPDFPageObjectHelper>::iterator iter = for (std::vector<QPDFPageObjectHelper>::iterator iter = pages.begin();
pages.begin(); iter != pages.end();
iter != pages.end(); ++iter) ++iter) {
{
QPDFPageObjectHelper& page(*iter); QPDFPageObjectHelper& page(*iter);
++pageno; ++pageno;
try try {
{
page.coalesceContentStreams(); page.coalesceContentStreams();
page.parseContents(&discard_contents); page.parseContents(&discard_contents);
page.getImages(); page.getImages();
@ -153,16 +154,13 @@ FuzzHelper::testPages()
afdh.getWidgetAnnotationsForPage(page); afdh.getWidgetAnnotationsForPage(page);
for (std::vector<QPDFAnnotationObjectHelper>::iterator annot_iter = for (std::vector<QPDFAnnotationObjectHelper>::iterator annot_iter =
annotations.begin(); annotations.begin();
annot_iter != annotations.end(); ++annot_iter) annot_iter != annotations.end();
{ ++annot_iter) {
QPDFAnnotationObjectHelper& aoh = *annot_iter; QPDFAnnotationObjectHelper& aoh = *annot_iter;
afdh.getFieldForAnnotation(aoh); afdh.getFieldForAnnotation(aoh);
} }
} } catch (QPDFExc& e) {
catch (QPDFExc& e) std::cerr << "page " << pageno << ": " << e.what() << std::endl;
{
std::cerr << "page " << pageno << ": "
<< e.what() << std::endl;
} }
} }
} }
@ -171,16 +169,15 @@ void
FuzzHelper::testOutlines() FuzzHelper::testOutlines()
{ {
PointerHolder<QPDF> q = getQpdf(); PointerHolder<QPDF> q = getQpdf();
std::list<std::vector<QPDFOutlineObjectHelper> > queue; std::list<std::vector<QPDFOutlineObjectHelper>> queue;
QPDFOutlineDocumentHelper odh(*q); QPDFOutlineDocumentHelper odh(*q);
queue.push_back(odh.getTopLevelOutlines()); queue.push_back(odh.getTopLevelOutlines());
while (! queue.empty()) while (!queue.empty()) {
{
std::vector<QPDFOutlineObjectHelper>& outlines = *(queue.begin()); std::vector<QPDFOutlineObjectHelper>& outlines = *(queue.begin());
for (std::vector<QPDFOutlineObjectHelper>::iterator iter = for (std::vector<QPDFOutlineObjectHelper>::iterator iter =
outlines.begin(); outlines.begin();
iter != outlines.end(); ++iter) iter != outlines.end();
{ ++iter) {
QPDFOutlineObjectHelper& ol = *iter; QPDFOutlineObjectHelper& ol = *iter;
ol.getDestPage(); ol.getDestPage();
queue.push_back(ol.getKids()); queue.push_back(ol.getKids());
@ -208,21 +205,17 @@ FuzzHelper::run()
// std::runtime_error. Throwing any other kind of exception, // std::runtime_error. Throwing any other kind of exception,
// segfaulting, or having a memory error (when built with // segfaulting, or having a memory error (when built with
// appropriate sanitizers) will all cause abnormal exit. // appropriate sanitizers) will all cause abnormal exit.
try try {
{
doChecks(); doChecks();
} } catch (QPDFExc const& e) {
catch (QPDFExc const& e)
{
std::cerr << "QPDFExc: " << e.what() << std::endl; std::cerr << "QPDFExc: " << e.what() << std::endl;
} } catch (std::runtime_error const& e) {
catch (std::runtime_error const& e)
{
std::cerr << "runtime_error: " << e.what() << std::endl; std::cerr << "runtime_error: " << e.what() << std::endl;
} }
} }
extern "C" int LLVMFuzzerTestOneInput(unsigned char const* data, size_t size) extern "C" int
LLVMFuzzerTestOneInput(unsigned char const* data, size_t size)
{ {
#ifndef _WIN32 #ifndef _WIN32
// Used by jpeg library to work around false positives in memory // Used by jpeg library to work around false positives in memory

View File

@ -34,17 +34,15 @@ FuzzHelper::doChecks()
void void
FuzzHelper::run() FuzzHelper::run()
{ {
try try {
{
doChecks(); doChecks();
} } catch (std::runtime_error const& e) {
catch (std::runtime_error const& e)
{
std::cerr << "runtime_error: " << e.what() << std::endl; std::cerr << "runtime_error: " << e.what() << std::endl;
} }
} }
extern "C" int LLVMFuzzerTestOneInput(unsigned char const* data, size_t size) extern "C" int
LLVMFuzzerTestOneInput(unsigned char const* data, size_t size)
{ {
FuzzHelper f(data, size); FuzzHelper f(data, size);
f.run(); f.run();

View File

@ -4,10 +4,10 @@
extern "C" int LLVMFuzzerTestOneInput(unsigned char const* data, size_t size); extern "C" int LLVMFuzzerTestOneInput(unsigned char const* data, size_t size);
int main(int argc, char **argv) int
main(int argc, char** argv)
{ {
for (int i = 1; i < argc; i++) for (int i = 1; i < argc; i++) {
{
PointerHolder<char> file_buf; PointerHolder<char> file_buf;
size_t size = 0; size_t size = 0;
QUtil::read_file_into_memory(argv[i], file_buf, size); QUtil::read_file_into_memory(argv[i], file_buf, size);

View File

@ -26,8 +26,8 @@ void
FuzzHelper::doChecks() FuzzHelper::doChecks()
{ {
Pl_Discard discard; Pl_Discard discard;
Pl_TIFFPredictor p("decoder", &discard, Pl_TIFFPredictor p(
Pl_TIFFPredictor::a_decode, 16, 1, 8); "decoder", &discard, Pl_TIFFPredictor::a_decode, 16, 1, 8);
p.write(const_cast<unsigned char*>(data), size); p.write(const_cast<unsigned char*>(data), size);
p.finish(); p.finish();
} }
@ -35,17 +35,15 @@ FuzzHelper::doChecks()
void void
FuzzHelper::run() FuzzHelper::run()
{ {
try try {
{
doChecks(); doChecks();
} } catch (std::runtime_error const& e) {
catch (std::runtime_error const& e)
{
std::cerr << "runtime_error: " << e.what() << std::endl; std::cerr << "runtime_error: " << e.what() << std::endl;
} }
} }
extern "C" int LLVMFuzzerTestOneInput(unsigned char const* data, size_t size) extern "C" int
LLVMFuzzerTestOneInput(unsigned char const* data, size_t size)
{ {
FuzzHelper f(data, size); FuzzHelper f(data, size);
f.run(); f.run();

View File

@ -25,8 +25,8 @@
#include <qpdf/DLL.h> #include <qpdf/DLL.h>
#include <qpdf/PointerHolder.hh> #include <qpdf/PointerHolder.hh>
#include <stddef.h>
#include <memory> #include <memory>
#include <stddef.h>
class Buffer class Buffer
{ {

View File

@ -22,8 +22,8 @@
#ifndef QPDF_BUFFERINPUTSOURCE_HH #ifndef QPDF_BUFFERINPUTSOURCE_HH
#define QPDF_BUFFERINPUTSOURCE_HH #define QPDF_BUFFERINPUTSOURCE_HH
#include <qpdf/InputSource.hh>
#include <qpdf/Buffer.hh> #include <qpdf/Buffer.hh>
#include <qpdf/InputSource.hh>
class BufferInputSource: public InputSource class BufferInputSource: public InputSource
{ {
@ -31,11 +31,11 @@ class BufferInputSource: public InputSource
// If own_memory is true, BufferInputSource will delete the buffer // If own_memory is true, BufferInputSource will delete the buffer
// when finished with it. Otherwise, the caller owns the memory. // when finished with it. Otherwise, the caller owns the memory.
QPDF_DLL QPDF_DLL
BufferInputSource(std::string const& description, Buffer* buf, BufferInputSource(
bool own_memory = false); std::string const& description, Buffer* buf, bool own_memory = false);
QPDF_DLL QPDF_DLL
BufferInputSource(std::string const& description, BufferInputSource(
std::string const& contents); std::string const& description, std::string const& contents);
QPDF_DLL QPDF_DLL
virtual ~BufferInputSource(); virtual ~BufferInputSource();
QPDF_DLL QPDF_DLL

View File

@ -29,16 +29,15 @@
/* Error Codes */ /* Error Codes */
enum qpdf_error_code_e enum qpdf_error_code_e {
{
qpdf_e_success = 0, qpdf_e_success = 0,
qpdf_e_internal, /* logic/programming error -- indicates bug */ qpdf_e_internal, /* logic/programming error -- indicates bug */
qpdf_e_system, /* I/O error, memory error, etc. */ qpdf_e_system, /* I/O error, memory error, etc. */
qpdf_e_unsupported, /* PDF feature not (yet) supported by qpdf */ qpdf_e_unsupported, /* PDF feature not (yet) supported by qpdf */
qpdf_e_password, /* incorrect password for encrypted file */ qpdf_e_password, /* incorrect password for encrypted file */
qpdf_e_damaged_pdf, /* syntax errors or other damage in PDF */ qpdf_e_damaged_pdf, /* syntax errors or other damage in PDF */
qpdf_e_pages, /* erroneous or unsupported pages structure */ qpdf_e_pages, /* erroneous or unsupported pages structure */
qpdf_e_object, /* type/bounds errors accessing objects */ qpdf_e_object, /* type/bounds errors accessing objects */
}; };
/* Object Types */ /* Object Types */
@ -75,62 +74,56 @@ enum qpdf_object_type_e {
/* Write Parameters. See QPDFWriter.hh for details. */ /* Write Parameters. See QPDFWriter.hh for details. */
enum qpdf_object_stream_e enum qpdf_object_stream_e {
{ qpdf_o_disable = 0, /* disable object streams */
qpdf_o_disable = 0, /* disable object streams */ qpdf_o_preserve, /* preserve object streams */
qpdf_o_preserve, /* preserve object streams */ qpdf_o_generate /* generate object streams */
qpdf_o_generate /* generate object streams */
}; };
enum qpdf_stream_data_e enum qpdf_stream_data_e {
{ qpdf_s_uncompress = 0, /* uncompress stream data */
qpdf_s_uncompress = 0, /* uncompress stream data */ qpdf_s_preserve, /* preserve stream data compression */
qpdf_s_preserve, /* preserve stream data compression */ qpdf_s_compress /* compress stream data */
qpdf_s_compress /* compress stream data */
}; };
/* Stream data flags */ /* Stream data flags */
/* See pipeStreamData in QPDFObjectHandle.hh for details on these flags. */ /* See pipeStreamData in QPDFObjectHandle.hh for details on these flags. */
enum qpdf_stream_encode_flags_e enum qpdf_stream_encode_flags_e {
{ qpdf_ef_compress = 1 << 0, /* compress uncompressed streams */
qpdf_ef_compress = 1 << 0, /* compress uncompressed streams */
qpdf_ef_normalize = 1 << 1, /* normalize content stream */ qpdf_ef_normalize = 1 << 1, /* normalize content stream */
}; };
enum qpdf_stream_decode_level_e enum qpdf_stream_decode_level_e {
{
/* These must be in order from less to more decoding. */ /* These must be in order from less to more decoding. */
qpdf_dl_none = 0, /* preserve all stream filters */ qpdf_dl_none = 0, /* preserve all stream filters */
qpdf_dl_generalized, /* decode general-purpose filters */ qpdf_dl_generalized, /* decode general-purpose filters */
qpdf_dl_specialized, /* also decode other non-lossy filters */ qpdf_dl_specialized, /* also decode other non-lossy filters */
qpdf_dl_all /* also decode lossy filters */ qpdf_dl_all /* also decode lossy filters */
}; };
/* R3 Encryption Parameters */ /* R3 Encryption Parameters */
enum qpdf_r3_print_e enum qpdf_r3_print_e {
{ qpdf_r3p_full = 0, /* allow all printing */
qpdf_r3p_full = 0, /* allow all printing */ qpdf_r3p_low, /* allow only low-resolution printing */
qpdf_r3p_low, /* allow only low-resolution printing */ qpdf_r3p_none /* allow no printing */
qpdf_r3p_none /* allow no printing */
}; };
/* qpdf_r3_modify_e doesn't allow the full flexibility of the spec. It /* qpdf_r3_modify_e doesn't allow the full flexibility of the spec. It
* corresponds to options in Acrobat 5's menus. The new interface in * corresponds to options in Acrobat 5's menus. The new interface in
* QPDFWriter offers more granularity and no longer uses this type. * QPDFWriter offers more granularity and no longer uses this type.
*/ */
enum qpdf_r3_modify_e /* Allowed changes: */ enum qpdf_r3_modify_e /* Allowed changes: */
{ {
qpdf_r3m_all = 0, /* All editing */ qpdf_r3m_all = 0, /* All editing */
qpdf_r3m_annotate, /* Comments, fill forms, signing, assembly */ qpdf_r3m_annotate, /* Comments, fill forms, signing, assembly */
qpdf_r3m_form, /* Fill forms, signing, assembly */ qpdf_r3m_form, /* Fill forms, signing, assembly */
qpdf_r3m_assembly, /* Only document assembly */ qpdf_r3m_assembly, /* Only document assembly */
qpdf_r3m_none /* No modifications */ qpdf_r3m_none /* No modifications */
}; };
/* Form field flags from the PDF spec */ /* Form field flags from the PDF spec */
enum pdf_form_field_flag_e enum pdf_form_field_flag_e {
{
/* flags that apply to all form fields */ /* flags that apply to all form fields */
ff_all_read_only = 1 << 0, ff_all_read_only = 1 << 0,
ff_all_required = 1 << 1, ff_all_required = 1 << 1,
@ -162,8 +155,7 @@ enum pdf_form_field_flag_e
/* Annotation flags from the PDF spec */ /* Annotation flags from the PDF spec */
enum pdf_annotation_flag_e enum pdf_annotation_flag_e {
{
an_invisible = 1 << 0, an_invisible = 1 << 0,
an_hidden = 1 << 1, an_hidden = 1 << 1,
an_print = 1 << 2, an_print = 1 << 2,
@ -177,8 +169,7 @@ enum pdf_annotation_flag_e
}; };
/* Encryption/password status for QPDFJob */ /* Encryption/password status for QPDFJob */
enum qpdf_encryption_status_e enum qpdf_encryption_status_e {
{
qpdf_es_encrypted = 1 << 0, qpdf_es_encrypted = 1 << 0,
qpdf_es_password_incorrect = 1 << 1 qpdf_es_password_incorrect = 1 << 1
}; };

View File

@ -32,7 +32,7 @@
#if (defined _WIN32 || defined __CYGWIN__) && defined(DLL_EXPORT) #if (defined _WIN32 || defined __CYGWIN__) && defined(DLL_EXPORT)
# define QPDF_DLL __declspec(dllexport) # define QPDF_DLL __declspec(dllexport)
#elif defined __GNUC__ #elif defined __GNUC__
# define QPDF_DLL __attribute__ ((visibility ("default"))) # define QPDF_DLL __attribute__((visibility("default")))
#else #else
# define QPDF_DLL # define QPDF_DLL
#endif #endif

View File

@ -23,12 +23,12 @@
#define QPDF_INPUTSOURCE_HH #define QPDF_INPUTSOURCE_HH
#include <qpdf/DLL.h> #include <qpdf/DLL.h>
#include <qpdf/Types.h>
#include <qpdf/PointerHolder.hh> #include <qpdf/PointerHolder.hh>
#include <qpdf/Types.h>
#include <memory>
#include <stdio.h> #include <stdio.h>
#include <string> #include <string>
#include <memory>
class QPDF_DLL_CLASS InputSource class QPDF_DLL_CLASS InputSource
{ {
@ -71,13 +71,17 @@ class QPDF_DLL_CLASS InputSource
// methods return true and leave the input source positioned // methods return true and leave the input source positioned
// wherever check() left it at the end of the matching pattern. // wherever check() left it at the end of the matching pattern.
QPDF_DLL QPDF_DLL
bool findFirst(char const* start_chars, bool findFirst(
qpdf_offset_t offset, size_t len, char const* start_chars,
Finder& finder); qpdf_offset_t offset,
size_t len,
Finder& finder);
QPDF_DLL QPDF_DLL
bool findLast(char const* start_chars, bool findLast(
qpdf_offset_t offset, size_t len, char const* start_chars,
Finder& finder); qpdf_offset_t offset,
size_t len,
Finder& finder);
virtual qpdf_offset_t findAndSkipNextEOL() = 0; virtual qpdf_offset_t findAndSkipNextEOL() = 0;
virtual std::string const& getName() const = 0; virtual std::string const& getName() const = 0;

View File

@ -38,12 +38,12 @@
#include <qpdf/DLL.h> #include <qpdf/DLL.h>
#include <qpdf/PointerHolder.hh> #include <qpdf/PointerHolder.hh>
#include <string>
#include <map>
#include <vector>
#include <list>
#include <functional> #include <functional>
#include <list>
#include <map>
#include <memory> #include <memory>
#include <string>
#include <vector>
class JSON class JSON
{ {
@ -134,14 +134,13 @@ class JSON
f_optional = 1 << 0, f_optional = 1 << 0,
}; };
QPDF_DLL QPDF_DLL
bool checkSchema(JSON schema, unsigned long flags, bool checkSchema(
std::list<std::string>& errors); JSON schema, unsigned long flags, std::list<std::string>& errors);
// Same as passing 0 for flags // Same as passing 0 for flags
QPDF_DLL QPDF_DLL
bool checkSchema(JSON schema, std::list<std::string>& errors); bool checkSchema(JSON schema, std::list<std::string>& errors);
// Create a JSON object from a string. // Create a JSON object from a string.
QPDF_DLL QPDF_DLL
static JSON parse(std::string const&); static JSON parse(std::string const&);
@ -198,11 +197,12 @@ class JSON
JSON(std::shared_ptr<JSON_value>); JSON(std::shared_ptr<JSON_value>);
static bool static bool checkSchemaInternal(
checkSchemaInternal(JSON_value* this_v, JSON_value* sch_v, JSON_value* this_v,
unsigned long flags, JSON_value* sch_v,
std::list<std::string>& errors, unsigned long flags,
std::string prefix); std::list<std::string>& errors,
std::string prefix);
class Members class Members
{ {
@ -222,5 +222,4 @@ class JSON
PointerHolder<Members> m; PointerHolder<Members> m;
}; };
#endif // JSON_HH #endif // JSON_HH

View File

@ -47,8 +47,8 @@
#include <qpdf/DLL.h> #include <qpdf/DLL.h>
#include <qpdf/PointerHolder.hh> #include <qpdf/PointerHolder.hh>
#include <string>
#include <memory> #include <memory>
#include <string>
class QPDF_DLL_CLASS Pipeline class QPDF_DLL_CLASS Pipeline
{ {

View File

@ -33,9 +33,9 @@
// For this pipeline, "next" may be null. If a next pointer is // For this pipeline, "next" may be null. If a next pointer is
// provided, this pipeline will also pass the data through to it. // provided, this pipeline will also pass the data through to it.
#include <qpdf/Buffer.hh>
#include <qpdf/Pipeline.hh> #include <qpdf/Pipeline.hh>
#include <qpdf/PointerHolder.hh> #include <qpdf/PointerHolder.hh>
#include <qpdf/Buffer.hh>
#include <memory> #include <memory>
@ -68,7 +68,7 @@ class Pl_Buffer: public Pipeline
// a buffer of size *len allocated with malloc(). It is the // a buffer of size *len allocated with malloc(). It is the
// caller's responsibility to call free() on the buffer. // caller's responsibility to call free() on the buffer.
QPDF_DLL QPDF_DLL
void getMallocBuffer(unsigned char **buf, size_t* len); void getMallocBuffer(unsigned char** buf, size_t* len);
private: private:
class Members class Members

View File

@ -25,8 +25,8 @@
// This pipeline is reusable; i.e., it is safe to call write() after // This pipeline is reusable; i.e., it is safe to call write() after
// calling finish(). // calling finish().
#include <qpdf/Types.h>
#include <qpdf/Pipeline.hh> #include <qpdf/Pipeline.hh>
#include <qpdf/Types.h>
class Pl_Count: public Pipeline class Pl_Count: public Pipeline
{ {

View File

@ -52,12 +52,14 @@ class Pl_DCT: public Pipeline
// Constructor for compressing image data // Constructor for compressing image data
QPDF_DLL QPDF_DLL
Pl_DCT(char const* identifier, Pipeline* next, Pl_DCT(
JDIMENSION image_width, char const* identifier,
JDIMENSION image_height, Pipeline* next,
int components, JDIMENSION image_width,
J_COLOR_SPACE color_space, JDIMENSION image_height,
CompressConfig* config_callback = 0); int components,
J_COLOR_SPACE color_space,
CompressConfig* config_callback = 0);
QPDF_DLL QPDF_DLL
virtual ~Pl_DCT(); virtual ~Pl_DCT();
@ -82,13 +84,14 @@ class Pl_DCT: public Pipeline
~Members(); ~Members();
private: private:
Members(action_e action, Members(
char const* buf_description, action_e action,
JDIMENSION image_width = 0, char const* buf_description,
JDIMENSION image_height = 0, JDIMENSION image_width = 0,
int components = 1, JDIMENSION image_height = 0,
J_COLOR_SPACE color_space = JCS_GRAYSCALE, int components = 1,
CompressConfig* config_callback = 0); J_COLOR_SPACE color_space = JCS_GRAYSCALE,
CompressConfig* config_callback = 0);
Members(Members const&); Members(Members const&);
action_e action; action_e action;

View File

@ -35,8 +35,11 @@ class Pl_Flate: public Pipeline
enum action_e { a_inflate, a_deflate }; enum action_e { a_inflate, a_deflate };
QPDF_DLL QPDF_DLL
Pl_Flate(char const* identifier, Pipeline* next, Pl_Flate(
action_e action, unsigned int out_bufsize = def_bufsize); char const* identifier,
Pipeline* next,
action_e action,
unsigned int out_bufsize = def_bufsize);
QPDF_DLL QPDF_DLL
virtual ~Pl_Flate(); virtual ~Pl_Flate();

View File

@ -24,10 +24,10 @@
#include <qpdf/Pipeline.hh> #include <qpdf/Pipeline.hh>
#include <qpdf/QPDFTokenizer.hh> #include <qpdf/Pl_Buffer.hh>
#include <qpdf/PointerHolder.hh> #include <qpdf/PointerHolder.hh>
#include <qpdf/QPDFObjectHandle.hh> #include <qpdf/QPDFObjectHandle.hh>
#include <qpdf/Pl_Buffer.hh> #include <qpdf/QPDFTokenizer.hh>
#include <memory> #include <memory>
@ -48,9 +48,10 @@ class Pl_QPDFTokenizer: public Pipeline
// pipeline that the token filter writes to. If next is not // pipeline that the token filter writes to. If next is not
// provided, any output written by the filter will be discarded. // provided, any output written by the filter will be discarded.
QPDF_DLL QPDF_DLL
Pl_QPDFTokenizer(char const* identifier, Pl_QPDFTokenizer(
QPDFObjectHandle::TokenFilter* filter, char const* identifier,
Pipeline* next = 0); QPDFObjectHandle::TokenFilter* filter,
Pipeline* next = 0);
QPDF_DLL QPDF_DLL
virtual ~Pl_QPDFTokenizer(); virtual ~Pl_QPDFTokenizer();
QPDF_DLL QPDF_DLL

View File

@ -30,8 +30,7 @@ class Pl_RunLength: public Pipeline
enum action_e { a_encode, a_decode }; enum action_e { a_encode, a_decode };
QPDF_DLL QPDF_DLL
Pl_RunLength(char const* identifier, Pipeline* next, Pl_RunLength(char const* identifier, Pipeline* next, action_e action);
action_e action);
QPDF_DLL QPDF_DLL
virtual ~Pl_RunLength(); virtual ~Pl_RunLength();

View File

@ -187,18 +187,16 @@ class PointerHolder
} }
~Data() ~Data()
{ {
if (array) if (array) {
{ delete[] this->pointer;
delete [] this->pointer; } else {
}
else
{
delete this->pointer; delete this->pointer;
} }
} }
T* pointer; T* pointer;
bool array; bool array;
int refcount; int refcount;
private: private:
Data(Data const&) = delete; Data(Data const&) = delete;
Data& operator=(Data const&) = delete; Data& operator=(Data const&) = delete;
@ -208,7 +206,7 @@ class PointerHolder
#if POINTERHOLDER_TRANSITION >= 1 #if POINTERHOLDER_TRANSITION >= 1
explicit explicit
#endif // POINTERHOLDER_TRANSITION >= 1 #endif // POINTERHOLDER_TRANSITION >= 1
PointerHolder(T* pointer = 0) PointerHolder(T* pointer = 0)
{ {
this->init(new Data(pointer, false)); this->init(new Data(pointer, false));
} }
@ -222,16 +220,17 @@ class PointerHolder
{ {
this->copy(rhs); this->copy(rhs);
} }
PointerHolder& operator=(PointerHolder const& rhs) PointerHolder&
operator=(PointerHolder const& rhs)
{ {
if (this != &rhs) if (this != &rhs) {
{
this->destroy(); this->destroy();
this->copy(rhs); this->copy(rhs);
} }
return *this; return *this;
} }
PointerHolder& operator=(decltype(nullptr)) PointerHolder&
operator=(decltype(nullptr))
{ {
this->operator=(PointerHolder<T>()); this->operator=(PointerHolder<T>());
return *this; return *this;
@ -240,21 +239,25 @@ class PointerHolder
{ {
this->destroy(); this->destroy();
} }
bool operator==(PointerHolder const& rhs) const bool
operator==(PointerHolder const& rhs) const
{ {
return this->data->pointer == rhs.data->pointer; return this->data->pointer == rhs.data->pointer;
} }
bool operator==(decltype(nullptr)) const bool
operator==(decltype(nullptr)) const
{ {
return this->data->pointer == nullptr; return this->data->pointer == nullptr;
} }
bool operator<(PointerHolder const& rhs) const bool
operator<(PointerHolder const& rhs) const
{ {
return this->data->pointer < rhs.data->pointer; return this->data->pointer < rhs.data->pointer;
} }
// get() is for interface compatibility with std::shared_ptr // get() is for interface compatibility with std::shared_ptr
T* get() const T*
get() const
{ {
return this->data->pointer; return this->data->pointer;
} }
@ -264,70 +267,79 @@ class PointerHolder
#if POINTERHOLDER_TRANSITION >= 2 #if POINTERHOLDER_TRANSITION >= 2
[[deprecated("use PointerHolder<T>::get() instead of getPointer()")]] [[deprecated("use PointerHolder<T>::get() instead of getPointer()")]]
#endif // POINTERHOLDER_TRANSITION >= 2 #endif // POINTERHOLDER_TRANSITION >= 2
T* getPointer() T*
getPointer()
{ {
return this->data->pointer; return this->data->pointer;
} }
#if POINTERHOLDER_TRANSITION >= 2 #if POINTERHOLDER_TRANSITION >= 2
[[deprecated("use PointerHolder<T>::get() instead of getPointer()")]] [[deprecated("use PointerHolder<T>::get() instead of getPointer()")]]
#endif // POINTERHOLDER_TRANSITION >= 2 #endif // POINTERHOLDER_TRANSITION >= 2
T const* getPointer() const T const*
getPointer() const
{ {
return this->data->pointer; return this->data->pointer;
} }
#if POINTERHOLDER_TRANSITION >= 2 #if POINTERHOLDER_TRANSITION >= 2
[[deprecated("use use_count() instead of getRefcount()")]] [[deprecated("use use_count() instead of getRefcount()")]]
#endif // POINTERHOLDER_TRANSITION >= 2 #endif // POINTERHOLDER_TRANSITION >= 2
int getRefcount() const int
getRefcount() const
{ {
return this->data->refcount; return this->data->refcount;
} }
// use_count() is for compatibility with std::shared_ptr // use_count() is for compatibility with std::shared_ptr
long use_count() long
use_count()
{ {
return static_cast<long>(this->data->refcount); return static_cast<long>(this->data->refcount);
} }
T const& operator*() const T const&
operator*() const
{ {
return *this->data->pointer; return *this->data->pointer;
} }
T& operator*() T&
operator*()
{ {
return *this->data->pointer; return *this->data->pointer;
} }
T const* operator->() const T const*
operator->() const
{ {
return this->data->pointer; return this->data->pointer;
} }
T* operator->() T*
operator->()
{ {
return this->data->pointer; return this->data->pointer;
} }
private: private:
void init(Data* data) void
init(Data* data)
{ {
this->data = data; this->data = data;
++this->data->refcount; ++this->data->refcount;
} }
void copy(PointerHolder const& rhs) void
copy(PointerHolder const& rhs)
{ {
this->init(rhs.data); this->init(rhs.data);
} }
void destroy() void
destroy()
{ {
bool gone = false; bool gone = false;
{ {
if (--this->data->refcount == 0) if (--this->data->refcount == 0) {
{
gone = true; gone = true;
} }
} }
if (gone) if (gone) {
{
delete this->data; delete this->data;
} }
} }
@ -335,7 +347,7 @@ class PointerHolder
Data* data; Data* data;
}; };
template<typename T, typename... _Args> template <typename T, typename... _Args>
inline PointerHolder<T> inline PointerHolder<T>
make_pointer_holder(_Args&&... __args) make_pointer_holder(_Args&&... __args)
{ {

View File

@ -24,12 +24,12 @@
#include <qpdf/DLL.h> #include <qpdf/DLL.h>
#include <qpdf/Types.h> #include <qpdf/Types.h>
#include <stdexcept> #include <cassert>
#include <iostream> #include <iostream>
#include <limits> #include <limits>
#include <sstream>
#include <cassert>
#include <locale> #include <locale>
#include <sstream>
#include <stdexcept>
#include <type_traits> #include <type_traits>
// This namespace provides safe integer conversion that detects // This namespace provides safe integer conversion that detects
@ -51,9 +51,11 @@ namespace QIntC // QIntC = qpdf Integer Conversion
// throws a range_error otherwise. This class is specialized for // throws a range_error otherwise. This class is specialized for
// each permutation of signed/unsigned for the From and To // each permutation of signed/unsigned for the From and To
// classes. // classes.
template <typename From, typename To, template <
bool From_signed = std::numeric_limits<From>::is_signed, typename From,
bool To_signed = std::numeric_limits<To>::is_signed> typename To,
bool From_signed = std::numeric_limits<From>::is_signed,
bool To_signed = std::numeric_limits<To>::is_signed>
class IntConverter class IntConverter
{ {
}; };
@ -62,17 +64,16 @@ namespace QIntC // QIntC = qpdf Integer Conversion
class IntConverter<From, To, false, false> class IntConverter<From, To, false, false>
{ {
public: public:
static To convert(From const& i) static To
convert(From const& i)
{ {
// From and To are both unsigned. // From and To are both unsigned.
if (i > std::numeric_limits<To>::max()) if (i > std::numeric_limits<To>::max()) {
{
std::ostringstream msg; std::ostringstream msg;
msg.imbue(std::locale::classic()); msg.imbue(std::locale::classic());
msg << "integer out of range converting " << i msg << "integer out of range converting " << i << " from a "
<< " from a " << sizeof(From) << "-byte unsigned type to a " << sizeof(To)
<< sizeof(From) << "-byte unsigned type to a " << "-byte unsigned type";
<< sizeof(To) << "-byte unsigned type";
throw std::range_error(msg.str()); throw std::range_error(msg.str());
} }
return static_cast<To>(i); return static_cast<To>(i);
@ -83,18 +84,17 @@ namespace QIntC // QIntC = qpdf Integer Conversion
class IntConverter<From, To, true, true> class IntConverter<From, To, true, true>
{ {
public: public:
static To convert(From const& i) static To
convert(From const& i)
{ {
// From and To are both signed. // From and To are both signed.
if ((i < std::numeric_limits<To>::min()) || if ((i < std::numeric_limits<To>::min()) ||
(i > std::numeric_limits<To>::max())) (i > std::numeric_limits<To>::max())) {
{
std::ostringstream msg; std::ostringstream msg;
msg.imbue(std::locale::classic()); msg.imbue(std::locale::classic());
msg << "integer out of range converting " << i msg << "integer out of range converting " << i << " from a "
<< " from a " << sizeof(From) << "-byte signed type to a " << sizeof(To)
<< sizeof(From) << "-byte signed type to a " << "-byte signed type";
<< sizeof(To) << "-byte signed type";
throw std::range_error(msg.str()); throw std::range_error(msg.str());
} }
return static_cast<To>(i); return static_cast<To>(i);
@ -105,20 +105,19 @@ namespace QIntC // QIntC = qpdf Integer Conversion
class IntConverter<From, To, true, false> class IntConverter<From, To, true, false>
{ {
public: public:
static To convert(From const& i) static To
convert(From const& i)
{ {
// From is signed, and To is unsigned. If i > 0, it's safe to // From is signed, and To is unsigned. If i > 0, it's safe to
// convert it to the corresponding unsigned type and to // convert it to the corresponding unsigned type and to
// compare with To's max. // compare with To's max.
auto ii = static_cast<typename to_u<From>::type>(i); auto ii = static_cast<typename to_u<From>::type>(i);
if ((i < 0) || (ii > std::numeric_limits<To>::max())) if ((i < 0) || (ii > std::numeric_limits<To>::max())) {
{
std::ostringstream msg; std::ostringstream msg;
msg.imbue(std::locale::classic()); msg.imbue(std::locale::classic());
msg << "integer out of range converting " << i msg << "integer out of range converting " << i << " from a "
<< " from a " << sizeof(From) << "-byte signed type to a " << sizeof(To)
<< sizeof(From) << "-byte signed type to a " << "-byte unsigned type";
<< sizeof(To) << "-byte unsigned type";
throw std::range_error(msg.str()); throw std::range_error(msg.str());
} }
return static_cast<To>(i); return static_cast<To>(i);
@ -129,20 +128,19 @@ namespace QIntC // QIntC = qpdf Integer Conversion
class IntConverter<From, To, false, true> class IntConverter<From, To, false, true>
{ {
public: public:
static To convert(From const& i) static To
convert(From const& i)
{ {
// From is unsigned, and to is signed. Convert To's max to the // From is unsigned, and to is signed. Convert To's max to the
// unsigned version of To and compare i against that. // unsigned version of To and compare i against that.
auto maxval = static_cast<typename to_u<To>::type>( auto maxval = static_cast<typename to_u<To>::type>(
std::numeric_limits<To>::max()); std::numeric_limits<To>::max());
if (i > maxval) if (i > maxval) {
{
std::ostringstream msg; std::ostringstream msg;
msg.imbue(std::locale::classic()); msg.imbue(std::locale::classic());
msg << "integer out of range converting " << i msg << "integer out of range converting " << i << " from a "
<< " from a " << sizeof(From) << "-byte unsigned type to a " << sizeof(To)
<< sizeof(From) << "-byte unsigned type to a " << "-byte signed type";
<< sizeof(To) << "-byte signed type";
throw std::range_error(msg.str()); throw std::range_error(msg.str());
} }
return static_cast<To>(i); return static_cast<To>(i);
@ -152,97 +150,105 @@ namespace QIntC // QIntC = qpdf Integer Conversion
// Specific converters. The return type of each function must match // Specific converters. The return type of each function must match
// the second template parameter to IntConverter. // the second template parameter to IntConverter.
template <typename T> template <typename T>
char to_char(T const& i) char
to_char(T const& i)
{ {
return IntConverter<T, char>::convert(i); return IntConverter<T, char>::convert(i);
} }
template <typename T> template <typename T>
unsigned char to_uchar(T const& i) unsigned char
to_uchar(T const& i)
{ {
return IntConverter<T, unsigned char>::convert(i); return IntConverter<T, unsigned char>::convert(i);
} }
template <typename T> template <typename T>
short to_short(T const& i) short
to_short(T const& i)
{ {
return IntConverter<T, short>::convert(i); return IntConverter<T, short>::convert(i);
} }
template <typename T> template <typename T>
unsigned short to_ushort(T const& i) unsigned short
to_ushort(T const& i)
{ {
return IntConverter<T, unsigned short>::convert(i); return IntConverter<T, unsigned short>::convert(i);
} }
template <typename T> template <typename T>
int to_int(T const& i) int
to_int(T const& i)
{ {
return IntConverter<T, int>::convert(i); return IntConverter<T, int>::convert(i);
} }
template <typename T> template <typename T>
unsigned int to_uint(T const& i) unsigned int
to_uint(T const& i)
{ {
return IntConverter<T, unsigned int>::convert(i); return IntConverter<T, unsigned int>::convert(i);
} }
template <typename T> template <typename T>
size_t to_size(T const& i) size_t
to_size(T const& i)
{ {
return IntConverter<T, size_t>::convert(i); return IntConverter<T, size_t>::convert(i);
} }
template <typename T> template <typename T>
qpdf_offset_t to_offset(T const& i) qpdf_offset_t
to_offset(T const& i)
{ {
return IntConverter<T, qpdf_offset_t>::convert(i); return IntConverter<T, qpdf_offset_t>::convert(i);
} }
template <typename T> template <typename T>
long to_long(T const& i) long
to_long(T const& i)
{ {
return IntConverter<T, long >::convert(i); return IntConverter<T, long>::convert(i);
} }
template <typename T> template <typename T>
unsigned long to_ulong(T const& i) unsigned long
to_ulong(T const& i)
{ {
return IntConverter<T, unsigned long >::convert(i); return IntConverter<T, unsigned long>::convert(i);
} }
template <typename T> template <typename T>
long long to_longlong(T const& i) long long
to_longlong(T const& i)
{ {
return IntConverter<T, long long>::convert(i); return IntConverter<T, long long>::convert(i);
} }
template <typename T> template <typename T>
unsigned long long to_ulonglong(T const& i) unsigned long long
to_ulonglong(T const& i)
{ {
return IntConverter<T, unsigned long long>::convert(i); return IntConverter<T, unsigned long long>::convert(i);
} }
template <typename T> template <typename T>
void range_check(T const& cur, T const& delta) void
range_check(T const& cur, T const& delta)
{ {
if ((delta > 0) != (cur > 0)) if ((delta > 0) != (cur > 0)) {
{
return; return;
} }
if ((delta > 0) && if ((delta > 0) && ((std::numeric_limits<T>::max() - cur) < delta)) {
((std::numeric_limits<T>::max() - cur) < delta))
{
std::ostringstream msg; std::ostringstream msg;
msg.imbue(std::locale::classic()); msg.imbue(std::locale::classic());
msg << "adding " << delta << " to " << cur msg << "adding " << delta << " to " << cur
<< " would cause an integer overflow"; << " would cause an integer overflow";
throw std::range_error(msg.str()); throw std::range_error(msg.str());
} } else if (
else if ((delta < 0) && (delta < 0) && ((std::numeric_limits<T>::min() - cur) > delta)) {
((std::numeric_limits<T>::min() - cur) > delta))
{
std::ostringstream msg; std::ostringstream msg;
msg.imbue(std::locale::classic()); msg.imbue(std::locale::classic());
msg << "adding " << delta << " to " << cur msg << "adding " << delta << " to " << cur
@ -252,25 +258,21 @@ namespace QIntC // QIntC = qpdf Integer Conversion
} }
template <typename T> template <typename T>
void range_check_substract(T const& cur, T const& delta) void
range_check_substract(T const& cur, T const& delta)
{ {
if ((delta >= 0) == (cur >= 0)) if ((delta >= 0) == (cur >= 0)) {
{
return; return;
} }
if ((delta > 0) && if ((delta > 0) && ((std::numeric_limits<T>::min() + delta) > cur)) {
((std::numeric_limits<T>::min() + delta) > cur))
{
std::ostringstream msg; std::ostringstream msg;
msg.imbue(std::locale::classic()); msg.imbue(std::locale::classic());
msg << "subtracting " << delta << " from " << cur msg << "subtracting " << delta << " from " << cur
<< " would cause an integer underflow"; << " would cause an integer underflow";
throw std::range_error(msg.str()); throw std::range_error(msg.str());
} } else if (
else if ((delta < 0) && (delta < 0) && ((std::numeric_limits<T>::max() + delta) < cur)) {
((std::numeric_limits<T>::max() + delta) < cur))
{
std::ostringstream msg; std::ostringstream msg;
msg.imbue(std::locale::classic()); msg.imbue(std::locale::classic());
msg << "subtracting " << delta << " from " << cur msg << "subtracting " << delta << " from " << cur
@ -278,6 +280,6 @@ namespace QIntC // QIntC = qpdf Integer Conversion
throw std::range_error(msg.str()); throw std::range_error(msg.str());
} }
} }
}; }; // namespace QIntC
#endif // QINTC_HH #endif // QINTC_HH

View File

@ -25,26 +25,25 @@
#include <qpdf/DLL.h> #include <qpdf/DLL.h>
#include <qpdf/Types.h> #include <qpdf/Types.h>
#include <functional>
#include <iostream>
#include <list>
#include <map>
#include <memory>
#include <stdio.h> #include <stdio.h>
#include <string> #include <string>
#include <map>
#include <list>
#include <iostream>
#include <vector> #include <vector>
#include <functional>
#include <memory>
#include <qpdf/QIntC.hh>
#include <qpdf/QPDFExc.hh>
#include <qpdf/QPDFObjectHandle.hh>
#include <qpdf/QPDFObjGen.hh>
#include <qpdf/QPDFXRefEntry.hh>
#include <qpdf/QPDFObjectHandle.hh>
#include <qpdf/QPDFTokenizer.hh>
#include <qpdf/QPDFStreamFilter.hh>
#include <qpdf/Buffer.hh> #include <qpdf/Buffer.hh>
#include <qpdf/InputSource.hh> #include <qpdf/InputSource.hh>
#include <qpdf/PDFVersion.hh> #include <qpdf/PDFVersion.hh>
#include <qpdf/QIntC.hh>
#include <qpdf/QPDFExc.hh>
#include <qpdf/QPDFObjGen.hh>
#include <qpdf/QPDFObjectHandle.hh>
#include <qpdf/QPDFStreamFilter.hh>
#include <qpdf/QPDFTokenizer.hh>
#include <qpdf/QPDFXRefEntry.hh>
class QPDF_Stream; class QPDF_Stream;
class BitStream; class BitStream;
@ -87,24 +86,29 @@ class QPDF
// file will be closed at the end. Otherwise, the caller is // file will be closed at the end. Otherwise, the caller is
// responsible for closing the file. // responsible for closing the file.
QPDF_DLL QPDF_DLL
void processFile(char const* description, FILE* file, void processFile(
bool close_file, char const* password = 0); char const* description,
FILE* file,
bool close_file,
char const* password = 0);
// Parse a PDF file loaded into a memory buffer. This works // Parse a PDF file loaded into a memory buffer. This works
// exactly like processFile except that the PDF file is in memory // exactly like processFile except that the PDF file is in memory
// instead of on disk. The description appears in any warning or // instead of on disk. The description appears in any warning or
// error message in place of the file name. // error message in place of the file name.
QPDF_DLL QPDF_DLL
void processMemoryFile(char const* description, void processMemoryFile(
char const* buf, size_t length, char const* description,
char const* password = 0); char const* buf,
size_t length,
char const* password = 0);
// Parse a PDF file loaded from a custom InputSource. If you have // Parse a PDF file loaded from a custom InputSource. If you have
// your own method of retrieving a PDF file, you can subclass // your own method of retrieving a PDF file, you can subclass
// InputSource and use this method. // InputSource and use this method.
QPDF_DLL QPDF_DLL
void processInputSource(PointerHolder<InputSource>, void
char const* password = 0); processInputSource(PointerHolder<InputSource>, char const* password = 0);
// Close or otherwise release the input source. Once this has been // Close or otherwise release the input source. Once this has been
// called, no other methods of qpdf can be called safely except // called, no other methods of qpdf can be called safely except
@ -149,7 +153,7 @@ class QPDF
QPDF_DLL QPDF_DLL
static void registerStreamFilter( static void registerStreamFilter(
std::string const& filter_name, std::string const& filter_name,
std::function<std::shared_ptr<QPDFStreamFilter> ()> factory); std::function<std::shared_ptr<QPDFStreamFilter>()> factory);
// Parameter settings // Parameter settings
@ -312,8 +316,7 @@ class QPDF
QPDF_DLL QPDF_DLL
void swapObjects(QPDFObjGen const& og1, QPDFObjGen const& og2); void swapObjects(QPDFObjGen const& og1, QPDFObjGen const& og2);
QPDF_DLL QPDF_DLL
void swapObjects(int objid1, int generation1, void swapObjects(int objid1, int generation1, int objid2, int generation2);
int objid2, int generation2);
// Replace a reserved object. This is a wrapper around // Replace a reserved object. This is a wrapper around
// replaceObject but it guarantees that the underlying object is a // replaceObject but it guarantees that the underlying object is a
@ -321,8 +324,7 @@ class QPDF
// to replacement. // to replacement.
QPDF_DLL QPDF_DLL
void void
replaceReserved(QPDFObjectHandle reserved, replaceReserved(QPDFObjectHandle reserved, QPDFObjectHandle replacement);
QPDFObjectHandle replacement);
// Copy an object from another QPDF to this one. Starting with // Copy an object from another QPDF to this one. Starting with
// qpdf version 8.3.0, it is no longer necessary to keep the // qpdf version 8.3.0, it is no longer necessary to keep the
@ -377,13 +379,19 @@ class QPDF
class EncryptionData class EncryptionData
{ {
public: public:
// This class holds data read from the encryption dictionary. // This class holds data read from the encryption dictionary.
EncryptionData(int V, int R, int Length_bytes, int P, EncryptionData(
std::string const& O, std::string const& U, int V,
std::string const& OE, std::string const& UE, int R,
std::string const& Perms, int Length_bytes,
std::string const& id1, bool encrypt_metadata) : int P,
std::string const& O,
std::string const& U,
std::string const& OE,
std::string const& UE,
std::string const& Perms,
std::string const& id1,
bool encrypt_metadata) :
V(V), V(V),
R(R), R(R),
Length_bytes(Length_bytes), Length_bytes(Length_bytes),
@ -412,11 +420,12 @@ class QPDF
void setO(std::string const&); void setO(std::string const&);
void setU(std::string const&); void setU(std::string const&);
void setV5EncryptionParameters(std::string const& O, void setV5EncryptionParameters(
std::string const& OE, std::string const& O,
std::string const& U, std::string const& OE,
std::string const& UE, std::string const& U,
std::string const& Perms); std::string const& UE,
std::string const& Perms);
private: private:
EncryptionData(EncryptionData const&) = delete; EncryptionData(EncryptionData const&) = delete;
@ -442,10 +451,13 @@ class QPDF
bool isEncrypted(int& R, int& P); bool isEncrypted(int& R, int& P);
QPDF_DLL QPDF_DLL
bool isEncrypted(int& R, int& P, int& V, bool isEncrypted(
encryption_method_e& stream_method, int& R,
encryption_method_e& string_method, int& P,
encryption_method_e& file_method); int& V,
encryption_method_e& stream_method,
encryption_method_e& string_method,
encryption_method_e& file_method);
QPDF_DLL QPDF_DLL
bool ownerPasswordMatched() const; bool ownerPasswordMatched() const;
@ -480,26 +492,44 @@ class QPDF
static void trim_user_password(std::string& user_password); static void trim_user_password(std::string& user_password);
QPDF_DLL QPDF_DLL
static std::string compute_data_key( static std::string compute_data_key(
std::string const& encryption_key, int objid, int generation, std::string const& encryption_key,
bool use_aes, int encryption_V, int encryption_R); int objid,
int generation,
bool use_aes,
int encryption_V,
int encryption_R);
QPDF_DLL QPDF_DLL
static std::string compute_encryption_key( static std::string compute_encryption_key(
std::string const& password, EncryptionData const& data); std::string const& password, EncryptionData const& data);
QPDF_DLL QPDF_DLL
static void compute_encryption_O_U( static void compute_encryption_O_U(
char const* user_password, char const* owner_password, char const* user_password,
int V, int R, int key_len, int P, bool encrypt_metadata, char const* owner_password,
int V,
int R,
int key_len,
int P,
bool encrypt_metadata,
std::string const& id1, std::string const& id1,
std::string& O, std::string& U); std::string& O,
std::string& U);
QPDF_DLL QPDF_DLL
static void compute_encryption_parameters_V5( static void compute_encryption_parameters_V5(
char const* user_password, char const* owner_password, char const* user_password,
int V, int R, int key_len, int P, bool encrypt_metadata, char const* owner_password,
int V,
int R,
int key_len,
int P,
bool encrypt_metadata,
std::string const& id1, std::string const& id1,
std::string& encryption_key, std::string& encryption_key,
std::string& O, std::string& U, std::string& O,
std::string& OE, std::string& UE, std::string& Perms); std::string& U,
std::string& OE,
std::string& UE,
std::string& Perms);
// Return the full user password as stored in the PDF file. For // Return the full user password as stored in the PDF file. For
// files encrypted with 40-bit or 128-bit keys, the user password // files encrypted with 40-bit or 128-bit keys, the user password
// can be recovered when the file is opened using the owner // can be recovered when the file is opened using the owner
@ -587,8 +617,9 @@ class QPDF
// keys. This is used by QPDFWriter to avoid creation of dangling // keys. This is used by QPDFWriter to avoid creation of dangling
// objects for stream dictionary keys it will be regenerating. // objects for stream dictionary keys it will be regenerating.
QPDF_DLL QPDF_DLL
void optimize(std::map<int, int> const& object_stream_data, void optimize(
bool allow_changes = true); std::map<int, int> const& object_stream_data,
bool allow_changes = true);
// ABI: make function optional and merge overloaded versions // ABI: make function optional and merge overloaded versions
QPDF_DLL QPDF_DLL
void optimize( void optimize(
@ -650,8 +681,8 @@ class QPDF
QPDF_DLL QPDF_DLL
void addPage(QPDFObjectHandle newpage, bool first); void addPage(QPDFObjectHandle newpage, bool first);
QPDF_DLL QPDF_DLL
void addPageAt(QPDFObjectHandle newpage, bool before, void
QPDFObjectHandle refpage); addPageAt(QPDFObjectHandle newpage, bool before, QPDFObjectHandle refpage);
QPDF_DLL QPDF_DLL
void removePage(QPDFObjectHandle page); void removePage(QPDFObjectHandle page);
// End legacy page helpers // End legacy page helpers
@ -661,9 +692,10 @@ class QPDF
class Writer class Writer
{ {
friend class QPDFWriter; friend class QPDFWriter;
private:
static void getLinearizedParts( private:
static void
getLinearizedParts(
QPDF& qpdf, QPDF& qpdf,
std::map<int, int> const& object_stream_data, std::map<int, int> const& object_stream_data,
std::vector<QPDFObjectHandle>& part4, std::vector<QPDFObjectHandle>& part4,
@ -672,28 +704,32 @@ class QPDF
std::vector<QPDFObjectHandle>& part8, std::vector<QPDFObjectHandle>& part8,
std::vector<QPDFObjectHandle>& part9) std::vector<QPDFObjectHandle>& part9)
{ {
qpdf.getLinearizedParts(object_stream_data, qpdf.getLinearizedParts(
part4, part6, part7, part8, part9); object_stream_data, part4, part6, part7, part8, part9);
} }
static void generateHintStream( static void
generateHintStream(
QPDF& qpdf, QPDF& qpdf,
std::map<int, QPDFXRefEntry> const& xref, std::map<int, QPDFXRefEntry> const& xref,
std::map<int, qpdf_offset_t> const& lengths, std::map<int, qpdf_offset_t> const& lengths,
std::map<int, int> const& obj_renumber, std::map<int, int> const& obj_renumber,
PointerHolder<Buffer>& hint_stream, PointerHolder<Buffer>& hint_stream,
int& S, int& O) int& S,
int& O)
{ {
return qpdf.generateHintStream(xref, lengths, obj_renumber, return qpdf.generateHintStream(
hint_stream, S, O); xref, lengths, obj_renumber, hint_stream, S, O);
} }
static void getObjectStreamData(QPDF& qpdf, std::map<int, int>& omap) static void
getObjectStreamData(QPDF& qpdf, std::map<int, int>& omap)
{ {
qpdf.getObjectStreamData(omap); qpdf.getObjectStreamData(omap);
} }
static std::vector<QPDFObjGen> getCompressibleObjGens(QPDF& qpdf) static std::vector<QPDFObjGen>
getCompressibleObjGens(QPDF& qpdf)
{ {
return qpdf.getCompressibleObjGens(); return qpdf.getCompressibleObjGens();
} }
@ -704,13 +740,15 @@ class QPDF
class Resolver class Resolver
{ {
friend class QPDFObjectHandle; friend class QPDFObjectHandle;
private: private:
static PointerHolder<QPDFObject> resolve( static PointerHolder<QPDFObject>
QPDF* qpdf, int objid, int generation) resolve(QPDF* qpdf, int objid, int generation)
{ {
return qpdf->resolve(objid, generation); return qpdf->resolve(objid, generation);
} }
static bool objectChanged( static bool
objectChanged(
QPDF* qpdf, QPDFObjGen const& og, PointerHolder<QPDFObject>& oph) QPDF* qpdf, QPDFObjGen const& og, PointerHolder<QPDFObject>& oph)
{ {
return qpdf->objectChanged(og, oph); return qpdf->objectChanged(og, oph);
@ -723,10 +761,13 @@ class QPDF
class StreamCopier class StreamCopier
{ {
friend class QPDFObjectHandle; friend class QPDFObjectHandle;
private: private:
static void copyStreamData(QPDF* qpdf, static void
QPDFObjectHandle const& dest, copyStreamData(
QPDFObjectHandle const& src) QPDF* qpdf,
QPDFObjectHandle const& dest,
QPDFObjectHandle const& src)
{ {
qpdf->copyStreamData(dest, src); qpdf->copyStreamData(dest, src);
} }
@ -738,19 +779,18 @@ class QPDF
class ParseGuard class ParseGuard
{ {
friend class QPDFObjectHandle; friend class QPDFObjectHandle;
private: private:
ParseGuard(QPDF* qpdf) : ParseGuard(QPDF* qpdf) :
qpdf(qpdf) qpdf(qpdf)
{ {
if (qpdf) if (qpdf) {
{
qpdf->inParse(true); qpdf->inParse(true);
} }
} }
~ParseGuard() ~ParseGuard()
{ {
if (qpdf) if (qpdf) {
{
qpdf->inParse(false); qpdf->inParse(false);
} }
} }
@ -762,17 +802,29 @@ class QPDF
class Pipe class Pipe
{ {
friend class QPDF_Stream; friend class QPDF_Stream;
private: private:
static bool pipeStreamData(QPDF* qpdf, int objid, int generation, static bool
qpdf_offset_t offset, size_t length, pipeStreamData(
QPDFObjectHandle dict, QPDF* qpdf,
Pipeline* pipeline, int objid,
bool suppress_warnings, int generation,
bool will_retry) qpdf_offset_t offset,
size_t length,
QPDFObjectHandle dict,
Pipeline* pipeline,
bool suppress_warnings,
bool will_retry)
{ {
return qpdf->pipeStreamData( return qpdf->pipeStreamData(
objid, generation, offset, length, dict, pipeline, objid,
suppress_warnings, will_retry); generation,
offset,
length,
dict,
pipeline,
suppress_warnings,
will_retry);
} }
}; };
friend class Pipe; friend class Pipe;
@ -788,9 +840,10 @@ class QPDF
end_after_space(0) end_after_space(0)
{ {
} }
ObjCache(PointerHolder<QPDFObject> object, ObjCache(
qpdf_offset_t end_before_space, PointerHolder<QPDFObject> object,
qpdf_offset_t end_after_space) : qpdf_offset_t end_before_space,
qpdf_offset_t end_after_space) :
object(object), object(object),
end_before_space(end_before_space), end_before_space(end_before_space),
end_after_space(end_after_space) end_after_space(end_after_space)
@ -813,6 +866,7 @@ class QPDF
class EncryptionParameters class EncryptionParameters
{ {
friend class QPDF; friend class QPDF;
public: public:
EncryptionParameters(); EncryptionParameters();
@ -839,6 +893,7 @@ class QPDF
class ForeignStreamData class ForeignStreamData
{ {
friend class QPDF; friend class QPDF;
public: public:
ForeignStreamData( ForeignStreamData(
PointerHolder<EncryptionParameters> encp, PointerHolder<EncryptionParameters> encp,
@ -867,18 +922,21 @@ class QPDF
{ {
} }
virtual bool provideStreamData( virtual bool provideStreamData(
int objid, int generation, Pipeline* pipeline, int objid,
bool suppress_warnings, bool will_retry) override; int generation,
void registerForeignStream(QPDFObjGen const& local_og, Pipeline* pipeline,
QPDFObjectHandle foreign_stream); bool suppress_warnings,
void registerForeignStream(QPDFObjGen const& local_og, bool will_retry) override;
PointerHolder<ForeignStreamData>); void registerForeignStream(
QPDFObjGen const& local_og, QPDFObjectHandle foreign_stream);
void registerForeignStream(
QPDFObjGen const& local_og, PointerHolder<ForeignStreamData>);
private: private:
QPDF& destination_qpdf; QPDF& destination_qpdf;
std::map<QPDFObjGen, QPDFObjectHandle> foreign_streams; std::map<QPDFObjGen, QPDFObjectHandle> foreign_streams;
std::map<QPDFObjGen, std::map<QPDFObjGen, PointerHolder<ForeignStreamData>>
PointerHolder<ForeignStreamData> > foreign_stream_data; foreign_stream_data;
}; };
class StringDecrypter: public QPDFObjectHandle::StringDecrypter class StringDecrypter: public QPDFObjectHandle::StringDecrypter
@ -911,6 +969,7 @@ class QPDF
{ {
this->qpdf->m->resolving.erase(og); this->qpdf->m->resolving.erase(og);
} }
private: private:
QPDF* qpdf; QPDF* qpdf;
QPDFObjGen og; QPDFObjGen og;
@ -922,56 +981,72 @@ class QPDF
void setTrailer(QPDFObjectHandle obj); void setTrailer(QPDFObjectHandle obj);
void read_xref(qpdf_offset_t offset); void read_xref(qpdf_offset_t offset);
void reconstruct_xref(QPDFExc& e); void reconstruct_xref(QPDFExc& e);
bool parse_xrefFirst(std::string const& line, bool
int& obj, int& num, int& bytes); parse_xrefFirst(std::string const& line, int& obj, int& num, int& bytes);
bool parse_xrefEntry(std::string const& line, bool parse_xrefEntry(
qpdf_offset_t& f1, int& f2, char& type); std::string const& line, qpdf_offset_t& f1, int& f2, char& type);
qpdf_offset_t read_xrefTable(qpdf_offset_t offset); qpdf_offset_t read_xrefTable(qpdf_offset_t offset);
qpdf_offset_t read_xrefStream(qpdf_offset_t offset); qpdf_offset_t read_xrefStream(qpdf_offset_t offset);
qpdf_offset_t processXRefStream( qpdf_offset_t
qpdf_offset_t offset, QPDFObjectHandle& xref_stream); processXRefStream(qpdf_offset_t offset, QPDFObjectHandle& xref_stream);
void insertXrefEntry(int obj, int f0, qpdf_offset_t f1, int f2, void insertXrefEntry(
bool overwrite = false); int obj, int f0, qpdf_offset_t f1, int f2, bool overwrite = false);
void setLastObjectDescription(std::string const& description, void setLastObjectDescription(
int objid, int generation); std::string const& description, int objid, int generation);
QPDFObjectHandle readObject( QPDFObjectHandle readObject(
PointerHolder<InputSource>, std::string const& description, PointerHolder<InputSource>,
int objid, int generation, bool in_object_stream); std::string const& description,
int objid,
int generation,
bool in_object_stream);
size_t recoverStreamLength( size_t recoverStreamLength(
PointerHolder<InputSource> input, int objid, int generation, PointerHolder<InputSource> input,
int objid,
int generation,
qpdf_offset_t stream_offset); qpdf_offset_t stream_offset);
QPDFTokenizer::Token readToken(PointerHolder<InputSource>, QPDFTokenizer::Token
size_t max_len = 0); readToken(PointerHolder<InputSource>, size_t max_len = 0);
QPDFObjectHandle readObjectAtOffset( QPDFObjectHandle readObjectAtOffset(
bool attempt_recovery, bool attempt_recovery,
qpdf_offset_t offset, std::string const& description, qpdf_offset_t offset,
int exp_objid, int exp_generation, std::string const& description,
int& act_objid, int& act_generation); int exp_objid,
int exp_generation,
int& act_objid,
int& act_generation);
bool objectChanged(QPDFObjGen const& og, PointerHolder<QPDFObject>& oph); bool objectChanged(QPDFObjGen const& og, PointerHolder<QPDFObject>& oph);
PointerHolder<QPDFObject> resolve(int objid, int generation); PointerHolder<QPDFObject> resolve(int objid, int generation);
void resolveObjectsInStream(int obj_stream_number); void resolveObjectsInStream(int obj_stream_number);
void stopOnError(std::string const& message); void stopOnError(std::string const& message);
// Calls finish() on the pipeline when done but does not delete it // Calls finish() on the pipeline when done but does not delete it
bool pipeStreamData(int objid, int generation, bool pipeStreamData(
qpdf_offset_t offset, size_t length, int objid,
QPDFObjectHandle dict, int generation,
Pipeline* pipeline, qpdf_offset_t offset,
bool suppress_warnings, size_t length,
bool will_retry); QPDFObjectHandle dict,
Pipeline* pipeline,
bool suppress_warnings,
bool will_retry);
bool pipeForeignStreamData( bool pipeForeignStreamData(
PointerHolder<ForeignStreamData>, PointerHolder<ForeignStreamData>,
Pipeline*, bool suppress_warnings, bool will_retry); Pipeline*,
static bool pipeStreamData(PointerHolder<QPDF::EncryptionParameters> encp, bool suppress_warnings,
PointerHolder<InputSource> file, bool will_retry);
QPDF& qpdf_for_warning, static bool pipeStreamData(
int objid, int generation, PointerHolder<QPDF::EncryptionParameters> encp,
qpdf_offset_t offset, size_t length, PointerHolder<InputSource> file,
QPDFObjectHandle dict, QPDF& qpdf_for_warning,
Pipeline* pipeline, int objid,
bool suppress_warnings, int generation,
bool will_retry); qpdf_offset_t offset,
size_t length,
QPDFObjectHandle dict,
Pipeline* pipeline,
bool suppress_warnings,
bool will_retry);
// For QPDFWriter: // For QPDFWriter:
@ -985,11 +1060,13 @@ class QPDF
std::vector<QPDFObjectHandle>& part8, std::vector<QPDFObjectHandle>& part8,
std::vector<QPDFObjectHandle>& part9); std::vector<QPDFObjectHandle>& part9);
void generateHintStream(std::map<int, QPDFXRefEntry> const& xref, void generateHintStream(
std::map<int, qpdf_offset_t> const& lengths, std::map<int, QPDFXRefEntry> const& xref,
std::map<int, int> const& obj_renumber, std::map<int, qpdf_offset_t> const& lengths,
PointerHolder<Buffer>& hint_stream, std::map<int, int> const& obj_renumber,
int& S, int& O); PointerHolder<Buffer>& hint_stream,
int& S,
int& O);
// Map object to object stream that contains it // Map object to object stream that contains it
void getObjectStreamData(std::map<int, int>&); void getObjectStreamData(std::map<int, int>&);
@ -1000,45 +1077,51 @@ class QPDF
// methods to support page handling // methods to support page handling
void getAllPagesInternal(QPDFObjectHandle cur_pages, void getAllPagesInternal(
std::vector<QPDFObjectHandle>& result, QPDFObjectHandle cur_pages,
std::set<QPDFObjGen>& visited, std::vector<QPDFObjectHandle>& result,
std::set<QPDFObjGen>& seen); std::set<QPDFObjGen>& visited,
std::set<QPDFObjGen>& seen);
void insertPage(QPDFObjectHandle newpage, int pos); void insertPage(QPDFObjectHandle newpage, int pos);
void flattenPagesTree(); void flattenPagesTree();
void insertPageobjToPage(QPDFObjectHandle const& obj, int pos, void insertPageobjToPage(
bool check_duplicate); QPDFObjectHandle const& obj, int pos, bool check_duplicate);
// methods to support encryption -- implemented in QPDF_encryption.cc // methods to support encryption -- implemented in QPDF_encryption.cc
static encryption_method_e interpretCF( static encryption_method_e
PointerHolder<EncryptionParameters> encp, QPDFObjectHandle); interpretCF(PointerHolder<EncryptionParameters> encp, QPDFObjectHandle);
void initializeEncryption(); void initializeEncryption();
static std::string getKeyForObject( static std::string getKeyForObject(
PointerHolder<EncryptionParameters> encp, PointerHolder<EncryptionParameters> encp,
int objid, int generation, bool use_aes); int objid,
int generation,
bool use_aes);
void decryptString(std::string&, int objid, int generation); void decryptString(std::string&, int objid, int generation);
static std::string compute_encryption_key_from_password( static std::string compute_encryption_key_from_password(
std::string const& password, EncryptionData const& data); std::string const& password, EncryptionData const& data);
static std::string recover_encryption_key_with_password( static std::string recover_encryption_key_with_password(
std::string const& password, EncryptionData const& data); std::string const& password, EncryptionData const& data);
static std::string recover_encryption_key_with_password( static std::string recover_encryption_key_with_password(
std::string const& password, EncryptionData const& data, std::string const& password,
EncryptionData const& data,
bool& perms_valid); bool& perms_valid);
static void decryptStream( static void decryptStream(
PointerHolder<EncryptionParameters> encp, PointerHolder<EncryptionParameters> encp,
PointerHolder<InputSource> file, PointerHolder<InputSource> file,
QPDF& qpdf_for_warning, Pipeline*& pipeline, QPDF& qpdf_for_warning,
int objid, int generation, Pipeline*& pipeline,
int objid,
int generation,
QPDFObjectHandle& stream_dict, QPDFObjectHandle& stream_dict,
std::vector<std::shared_ptr<Pipeline>>& heap); std::vector<std::shared_ptr<Pipeline>>& heap);
// Methods to support object copying // Methods to support object copying
void reserveObjects(QPDFObjectHandle foreign, ObjCopier& obj_copier, void
bool top); reserveObjects(QPDFObjectHandle foreign, ObjCopier& obj_copier, bool top);
QPDFObjectHandle replaceForeignIndirectObjects( QPDFObjectHandle replaceForeignIndirectObjects(
QPDFObjectHandle foreign, ObjCopier& obj_copier, bool top); QPDFObjectHandle foreign, ObjCopier& obj_copier, bool top);
void copyStreamData( void
QPDFObjectHandle dest_stream, QPDFObjectHandle src_stream); copyStreamData(QPDFObjectHandle dest_stream, QPDFObjectHandle src_stream);
// Linearization Hint table structures. // Linearization Hint table structures.
// Naming conventions: // Naming conventions:
@ -1065,14 +1148,14 @@ class QPDF
{ {
} }
int delta_nobjects; // 1 int delta_nobjects; // 1
qpdf_offset_t delta_page_length; // 2 qpdf_offset_t delta_page_length; // 2
int nshared_objects; // 3 int nshared_objects; // 3
// vectors' sizes = nshared_objects // vectors' sizes = nshared_objects
std::vector<int> shared_identifiers; // 4 std::vector<int> shared_identifiers; // 4
std::vector<int> shared_numerators; // 5 std::vector<int> shared_numerators; // 5
qpdf_offset_t delta_content_offset; // 6 qpdf_offset_t delta_content_offset; // 6
qpdf_offset_t delta_content_length; // 7 qpdf_offset_t delta_content_length; // 7
}; };
// PDF 1.4: Table F.3 // PDF 1.4: Table F.3
@ -1095,19 +1178,19 @@ class QPDF
{ {
} }
int min_nobjects; // 1 int min_nobjects; // 1
qpdf_offset_t first_page_offset; // 2 qpdf_offset_t first_page_offset; // 2
int nbits_delta_nobjects; // 3 int nbits_delta_nobjects; // 3
int min_page_length; // 4 int min_page_length; // 4
int nbits_delta_page_length; // 5 int nbits_delta_page_length; // 5
int min_content_offset; // 6 int min_content_offset; // 6
int nbits_delta_content_offset; // 7 int nbits_delta_content_offset; // 7
int min_content_length; // 8 int min_content_length; // 8
int nbits_delta_content_length; // 9 int nbits_delta_content_length; // 9
int nbits_nshared_objects; // 10 int nbits_nshared_objects; // 10
int nbits_shared_identifier; // 11 int nbits_shared_identifier; // 11
int nbits_shared_numerator; // 12 int nbits_shared_numerator; // 12
int shared_denominator; // 13 int shared_denominator; // 13
// vector size is npages // vector size is npages
std::vector<HPageOffsetEntry> entries; std::vector<HPageOffsetEntry> entries;
}; };
@ -1123,9 +1206,9 @@ class QPDF
} }
// Item 3 is a 128-bit signature (unsupported by Acrobat) // Item 3 is a 128-bit signature (unsupported by Acrobat)
int delta_group_length; // 1 int delta_group_length; // 1
int signature_present; // 2 -- always 0 int signature_present; // 2 -- always 0
int nobjects_minus_one; // 4 -- always 0 int nobjects_minus_one; // 4 -- always 0
}; };
// PDF 1.4: Table F.5 // PDF 1.4: Table F.5
@ -1142,13 +1225,13 @@ class QPDF
{ {
} }
int first_shared_obj; // 1 int first_shared_obj; // 1
qpdf_offset_t first_shared_offset; // 2 qpdf_offset_t first_shared_offset; // 2
int nshared_first_page; // 3 int nshared_first_page; // 3
int nshared_total; // 4 int nshared_total; // 4
int nbits_nobjects; // 5 int nbits_nobjects; // 5
int min_group_length; // 6 int min_group_length; // 6
int nbits_delta_group_length; // 7 int nbits_delta_group_length; // 7
// vector size is nshared_total // vector size is nshared_total
std::vector<HSharedObjectEntry> entries; std::vector<HSharedObjectEntry> entries;
}; };
@ -1164,10 +1247,10 @@ class QPDF
{ {
} }
int first_object; // 1 int first_object; // 1
qpdf_offset_t first_object_offset; // 2 qpdf_offset_t first_object_offset; // 2
int nobjects; // 3 int nobjects; // 3
int group_length; // 4 int group_length; // 4
}; };
// Other linearization data structures // Other linearization data structures
@ -1261,15 +1344,13 @@ class QPDF
// No need for CHGeneric -- HGeneric is fine as is. // No need for CHGeneric -- HGeneric is fine as is.
// Data structures to support optimization -- implemented in // Data structures to support optimization -- implemented in
// QPDF_optimization.cc // QPDF_optimization.cc
class ObjUser class ObjUser
{ {
public: public:
enum user_e enum user_e {
{
ou_bad, ou_bad,
ou_page, ou_page,
ou_thumb, ou_thumb,
@ -1293,8 +1374,8 @@ class QPDF
bool operator<(ObjUser const&) const; bool operator<(ObjUser const&) const;
user_e ou_type; user_e ou_type;
int pageno; // if ou_page; int pageno; // if ou_page;
std::string key; // if ou_trailer_key or ou_root_key std::string key; // if ou_trailer_key or ou_root_key
}; };
class PatternFinder: public InputSource::Finder class PatternFinder: public InputSource::Finder
@ -1308,7 +1389,8 @@ class QPDF
virtual ~PatternFinder() virtual ~PatternFinder()
{ {
} }
virtual bool check() virtual bool
check()
{ {
return (this->qpdf.*checker)(); return (this->qpdf.*checker)();
} }
@ -1328,8 +1410,8 @@ class QPDF
void readLinearizationData(); void readLinearizationData();
bool checkLinearizationInternal(); bool checkLinearizationInternal();
void dumpLinearizationDataInternal(); void dumpLinearizationDataInternal();
QPDFObjectHandle readHintStream( QPDFObjectHandle
Pipeline&, qpdf_offset_t offset, size_t length); readHintStream(Pipeline&, qpdf_offset_t offset, size_t length);
void readHPageOffset(BitStream); void readHPageOffset(BitStream);
void readHSharedObject(BitStream); void readHSharedObject(BitStream);
void readHGeneric(BitStream, HGeneric&); void readHGeneric(BitStream, HGeneric&);
@ -1337,30 +1419,32 @@ class QPDF
qpdf_offset_t getLinearizationOffset(QPDFObjGen const&); qpdf_offset_t getLinearizationOffset(QPDFObjGen const&);
QPDFObjectHandle getUncompressedObject( QPDFObjectHandle getUncompressedObject(
QPDFObjectHandle&, std::map<int, int> const& object_stream_data); QPDFObjectHandle&, std::map<int, int> const& object_stream_data);
int lengthNextN(int first_object, int n, int lengthNextN(int first_object, int n, std::list<std::string>& errors);
std::list<std::string>& errors); void checkHPageOffset(
void checkHPageOffset(std::list<std::string>& errors, std::list<std::string>& errors,
std::list<std::string>& warnings, std::list<std::string>& warnings,
std::vector<QPDFObjectHandle> const& pages, std::vector<QPDFObjectHandle> const& pages,
std::map<int, int>& idx_to_obj); std::map<int, int>& idx_to_obj);
void checkHSharedObject(std::list<std::string>& warnings, void checkHSharedObject(
std::list<std::string>& errors, std::list<std::string>& warnings,
std::vector<QPDFObjectHandle> const& pages, std::list<std::string>& errors,
std::map<int, int>& idx_to_obj); std::vector<QPDFObjectHandle> const& pages,
std::map<int, int>& idx_to_obj);
void checkHOutlines(std::list<std::string>& warnings); void checkHOutlines(std::list<std::string>& warnings);
void dumpHPageOffset(); void dumpHPageOffset();
void dumpHSharedObject(); void dumpHSharedObject();
void dumpHGeneric(HGeneric&); void dumpHGeneric(HGeneric&);
qpdf_offset_t adjusted_offset(qpdf_offset_t offset); qpdf_offset_t adjusted_offset(qpdf_offset_t offset);
QPDFObjectHandle objGenToIndirect(QPDFObjGen const&); QPDFObjectHandle objGenToIndirect(QPDFObjGen const&);
void calculateLinearizationData( void
std::map<int, int> const& object_stream_data); calculateLinearizationData(std::map<int, int> const& object_stream_data);
void pushOutlinesToPart( void pushOutlinesToPart(
std::vector<QPDFObjectHandle>& part, std::vector<QPDFObjectHandle>& part,
std::set<QPDFObjGen>& lc_outlines, std::set<QPDFObjGen>& lc_outlines,
std::map<int, int> const& object_stream_data); std::map<int, int> const& object_stream_data);
int outputLengthNextN( int outputLengthNextN(
int in_object, int n, int in_object,
int n,
std::map<int, qpdf_offset_t> const& lengths, std::map<int, qpdf_offset_t> const& lengths,
std::map<int, int> const& obj_renumber); std::map<int, int> const& obj_renumber);
void calculateHPageOffset( void calculateHPageOffset(
@ -1379,37 +1463,46 @@ class QPDF
void writeHSharedObject(BitWriter&); void writeHSharedObject(BitWriter&);
void writeHGeneric(BitWriter&, HGeneric&); void writeHGeneric(BitWriter&, HGeneric&);
// Methods to support optimization // Methods to support optimization
void pushInheritedAttributesToPage(bool allow_changes, void
bool warn_skipped_keys); pushInheritedAttributesToPage(bool allow_changes, bool warn_skipped_keys);
void pushInheritedAttributesToPageInternal( void pushInheritedAttributesToPageInternal(
QPDFObjectHandle, QPDFObjectHandle,
std::map<std::string, std::vector<QPDFObjectHandle> >&, std::map<std::string, std::vector<QPDFObjectHandle>>&,
std::vector<QPDFObjectHandle>& all_pages, std::vector<QPDFObjectHandle>& all_pages,
bool allow_changes, bool warn_skipped_keys, bool allow_changes,
bool warn_skipped_keys,
std::set<QPDFObjGen>& visited); std::set<QPDFObjGen>& visited);
void updateObjectMaps( void updateObjectMaps(
ObjUser const& ou, QPDFObjectHandle oh, ObjUser const& ou,
QPDFObjectHandle oh,
std::function<int(QPDFObjectHandle&)> skip_stream_parameters); std::function<int(QPDFObjectHandle&)> skip_stream_parameters);
void updateObjectMapsInternal( void updateObjectMapsInternal(
ObjUser const& ou, QPDFObjectHandle oh, ObjUser const& ou,
QPDFObjectHandle oh,
std::function<int(QPDFObjectHandle&)> skip_stream_parameters, std::function<int(QPDFObjectHandle&)> skip_stream_parameters,
std::set<QPDFObjGen>& visited, bool top, std::set<QPDFObjGen>& visited,
bool top,
int depth); int depth);
void filterCompressedObjects(std::map<int, int> const& object_stream_data); void filterCompressedObjects(std::map<int, int> const& object_stream_data);
// Type conversion helper methods // Type conversion helper methods
template<typename T> static qpdf_offset_t toO(T const& i) template <typename T>
static qpdf_offset_t
toO(T const& i)
{ {
return QIntC::to_offset(i); return QIntC::to_offset(i);
} }
template<typename T> static size_t toS(T const& i) template <typename T>
static size_t
toS(T const& i)
{ {
return QIntC::to_size(i); return QIntC::to_size(i);
} }
template<typename T> static int toI(T const& i) template <typename T>
static int
toI(T const& i)
{ {
return QIntC::to_int(i); return QIntC::to_int(i);
} }
@ -1490,8 +1583,8 @@ class QPDF
std::vector<QPDFObjectHandle> part9; std::vector<QPDFObjectHandle> part9;
// Optimization data // Optimization data
std::map<ObjUser, std::set<QPDFObjGen> > obj_user_to_objects; std::map<ObjUser, std::set<QPDFObjGen>> obj_user_to_objects;
std::map<QPDFObjGen, std::set<ObjUser> > object_to_obj_users; std::map<QPDFObjGen, std::set<ObjUser>> object_to_obj_users;
}; };
// Keep all member variables inside the Members object, which we // Keep all member variables inside the Members object, which we

View File

@ -67,7 +67,6 @@
// the "/AcroForm" field entry until you find the annotation // the "/AcroForm" field entry until you find the annotation
// dictionary. // dictionary.
#include <qpdf/QPDFDocumentHelper.hh> #include <qpdf/QPDFDocumentHelper.hh>
#include <qpdf/DLL.h> #include <qpdf/DLL.h>
@ -144,8 +143,7 @@ class QPDFAcroFormDocumentHelper: public QPDFDocumentHelper
// information to be accurate, any changes to field names must be // information to be accurate, any changes to field names must be
// done through setFormFieldName() above. // done through setFormFieldName() above.
QPDF_DLL QPDF_DLL
std::set<QPDFObjGen> std::set<QPDFObjGen> getFieldsWithQualifiedName(std::string const& name);
getFieldsWithQualifiedName(std::string const& name);
// Return the annotations associated with a terminal field. Note // Return the annotations associated with a terminal field. Note
// that in the case of a field having a single annotation, the // that in the case of a field having a single annotation, the
@ -153,17 +151,17 @@ class QPDFAcroFormDocumentHelper: public QPDFDocumentHelper
// object for the field. // object for the field.
QPDF_DLL QPDF_DLL
std::vector<QPDFAnnotationObjectHelper> std::vector<QPDFAnnotationObjectHelper>
getAnnotationsForField(QPDFFormFieldObjectHelper); getAnnotationsForField(QPDFFormFieldObjectHelper);
// Return annotations of subtype /Widget for a page. // Return annotations of subtype /Widget for a page.
QPDF_DLL QPDF_DLL
std::vector<QPDFAnnotationObjectHelper> std::vector<QPDFAnnotationObjectHelper>
getWidgetAnnotationsForPage(QPDFPageObjectHelper); getWidgetAnnotationsForPage(QPDFPageObjectHelper);
// Return top-level form fields for a page. // Return top-level form fields for a page.
QPDF_DLL QPDF_DLL
std::vector<QPDFFormFieldObjectHelper> std::vector<QPDFFormFieldObjectHelper>
getFormFieldsForPage(QPDFPageObjectHelper); getFormFieldsForPage(QPDFPageObjectHelper);
// Return the terminal field that is associated with this // Return the terminal field that is associated with this
// annotation. If the annotation dictionary is merged with the // annotation. If the annotation dictionary is merged with the
@ -173,8 +171,7 @@ class QPDFAcroFormDocumentHelper: public QPDFDocumentHelper
// not be an associated field, and this method will return a // not be an associated field, and this method will return a
// helper associated with a null object (isNull() == true). // helper associated with a null object (isNull() == true).
QPDF_DLL QPDF_DLL
QPDFFormFieldObjectHelper QPDFFormFieldObjectHelper getFieldForAnnotation(QPDFAnnotationObjectHelper);
getFieldForAnnotation(QPDFAnnotationObjectHelper);
// Return the current value of /NeedAppearances. If // Return the current value of /NeedAppearances. If
// /NeedAppearances is missing, return false as that is how PDF // /NeedAppearances is missing, return false as that is how PDF
@ -260,30 +257,33 @@ class QPDFAcroFormDocumentHelper: public QPDFDocumentHelper
// happens with qpdf --split-pages. // happens with qpdf --split-pages.
[[deprecated("Use fixCopiedAnnotations instead")]] [[deprecated("Use fixCopiedAnnotations instead")]]
// ABI: delete this method // ABI: delete this method
QPDF_DLL QPDF_DLL void
void copyFieldsFromForeignPage( copyFieldsFromForeignPage(
QPDFPageObjectHelper foreign_page, QPDFPageObjectHelper foreign_page,
QPDFAcroFormDocumentHelper& foreign_afdh, QPDFAcroFormDocumentHelper& foreign_afdh,
std::vector<QPDFObjectHandle>* copied_fields = nullptr); std::vector<QPDFObjectHandle>* copied_fields = nullptr);
private: private:
void analyze(); void analyze();
void traverseField(QPDFObjectHandle field, void traverseField(
QPDFObjectHandle parent, QPDFObjectHandle field,
int depth, std::set<QPDFObjGen>& visited); QPDFObjectHandle parent,
int depth,
std::set<QPDFObjGen>& visited);
QPDFObjectHandle getOrCreateAcroForm(); QPDFObjectHandle getOrCreateAcroForm();
void adjustInheritedFields( void adjustInheritedFields(
QPDFObjectHandle obj, QPDFObjectHandle obj,
bool override_da, std::string const& from_default_da, bool override_da,
bool override_q, int from_default_q); std::string const& from_default_da,
bool override_q,
int from_default_q);
void adjustDefaultAppearances( void adjustDefaultAppearances(
QPDFObjectHandle obj, QPDFObjectHandle obj,
std::map<std::string, std::map<std::string, std::map<std::string, std::string>> const&
std::map<std::string, std::string>> const& dr_map); dr_map);
void adjustAppearanceStream( void adjustAppearanceStream(
QPDFObjectHandle stream, QPDFObjectHandle stream,
std::map<std::string, std::map<std::string, std::map<std::string, std::string>> dr_map);
std::map<std::string, std::string>> dr_map);
class Members class Members
{ {
@ -298,9 +298,8 @@ class QPDFAcroFormDocumentHelper: public QPDFDocumentHelper
Members(Members const&); Members(Members const&);
bool cache_valid; bool cache_valid;
std::map<QPDFObjGen, std::map<QPDFObjGen, std::vector<QPDFAnnotationObjectHelper>>
std::vector<QPDFAnnotationObjectHelper> field_to_annotations;
> field_to_annotations;
std::map<QPDFObjGen, QPDFFormFieldObjectHelper> annotation_to_field; std::map<QPDFObjGen, QPDFFormFieldObjectHelper> annotation_to_field;
std::map<QPDFObjGen, std::string> field_to_name; std::map<QPDFObjGen, std::string> field_to_name;
std::map<std::string, std::set<QPDFObjGen>> name_to_fields; std::map<std::string, std::set<QPDFObjGen>> name_to_fields;

View File

@ -22,8 +22,8 @@
#ifndef QPDFANNOTATIONOBJECTHELPER_HH #ifndef QPDFANNOTATIONOBJECTHELPER_HH
#define QPDFANNOTATIONOBJECTHELPER_HH #define QPDFANNOTATIONOBJECTHELPER_HH
#include <qpdf/QPDFObjectHelper.hh>
#include <qpdf/Constants.h> #include <qpdf/Constants.h>
#include <qpdf/QPDFObjectHelper.hh>
#include <qpdf/DLL.h> #include <qpdf/DLL.h>
@ -78,8 +78,8 @@ class QPDFAnnotationObjectHelper: public QPDFObjectHelper
// which appearance stream is desired. If not specified, the // which appearance stream is desired. If not specified, the
// appearance state in "/AS" will used. // appearance state in "/AS" will used.
QPDF_DLL QPDF_DLL
QPDFObjectHandle getAppearanceStream(std::string const& which, QPDFObjectHandle getAppearanceStream(
std::string const& state = ""); std::string const& which, std::string const& state = "");
// Generate text suitable for addition to the containing page's // Generate text suitable for addition to the containing page's
// content stream that draws this annotation's appearance stream // content stream that draws this annotation's appearance stream
@ -96,7 +96,8 @@ class QPDFAnnotationObjectHelper: public QPDFObjectHelper
// preparing to print. // preparing to print.
QPDF_DLL QPDF_DLL
std::string getPageContentForAppearance( std::string getPageContentForAppearance(
std::string const& name, int rotate, std::string const& name,
int rotate,
int required_flags = 0, int required_flags = 0,
int forbidden_flags = an_invisible | an_hidden); int forbidden_flags = an_invisible | an_hidden);

View File

@ -77,19 +77,22 @@ class QPDF_DLL_CLASS QPDFCryptoImpl
virtual void RC4_init(unsigned char const* key_data, int key_len = -1) = 0; virtual void RC4_init(unsigned char const* key_data, int key_len = -1) = 0;
// out_data = 0 means to encrypt/decrypt in place // out_data = 0 means to encrypt/decrypt in place
QPDF_DLL QPDF_DLL
virtual void RC4_process(unsigned char* in_data, size_t len, virtual void RC4_process(
unsigned char* out_data = 0) = 0; unsigned char* in_data, size_t len, unsigned char* out_data = 0) = 0;
QPDF_DLL QPDF_DLL
virtual void RC4_finalize() = 0; virtual void RC4_finalize() = 0;
static size_t constexpr rijndael_buf_size = 16; static size_t constexpr rijndael_buf_size = 16;
QPDF_DLL QPDF_DLL
virtual void rijndael_init( virtual void rijndael_init(
bool encrypt, unsigned char const* key_data, size_t key_len, bool encrypt,
bool cbc_mode, unsigned char* cbc_block) = 0; unsigned char const* key_data,
size_t key_len,
bool cbc_mode,
unsigned char* cbc_block) = 0;
QPDF_DLL QPDF_DLL
virtual void rijndael_process( virtual void
unsigned char* in_data, unsigned char* out_data) = 0; rijndael_process(unsigned char* in_data, unsigned char* out_data) = 0;
QPDF_DLL QPDF_DLL
virtual void rijndael_finalize() = 0; virtual void rijndael_finalize() = 0;
}; };

View File

@ -24,11 +24,11 @@
#include <qpdf/DLL.h> #include <qpdf/DLL.h>
#include <qpdf/QPDFCryptoImpl.hh> #include <qpdf/QPDFCryptoImpl.hh>
#include <string>
#include <map>
#include <set>
#include <memory>
#include <functional> #include <functional>
#include <map>
#include <memory>
#include <set>
#include <string>
// This class is part of qpdf's pluggable crypto provider support. // This class is part of qpdf's pluggable crypto provider support.
// Most users won't need to know or care about this class, but you can // Most users won't need to know or care about this class, but you can
@ -38,7 +38,6 @@
class QPDFCryptoProvider class QPDFCryptoProvider
{ {
public: public:
// Methods for getting and registering crypto implementations. // Methods for getting and registering crypto implementations.
// These methods are not thread-safe. // These methods are not thread-safe.
@ -50,15 +49,13 @@ class QPDFCryptoProvider
// Return an instance of the crypto provider registered using the // Return an instance of the crypto provider registered using the
// given name. // given name.
QPDF_DLL QPDF_DLL
static std::shared_ptr<QPDFCryptoImpl> static std::shared_ptr<QPDFCryptoImpl> getImpl(std::string const& name);
getImpl(std::string const& name);
// Register the given type (T) as a crypto implementation. T must // Register the given type (T) as a crypto implementation. T must
// be derived from QPDFCryptoImpl and must have a constructor that // be derived from QPDFCryptoImpl and must have a constructor that
// takes no arguments. // takes no arguments.
template<typename T> template <typename T>
QPDF_DLL QPDF_DLL static void registerImpl(std::string const& name);
static void registerImpl(std::string const& name);
// Set the crypto provider registered with the given name as the // Set the crypto provider registered with the given name as the
// default crypto implementation. // default crypto implementation.
@ -83,7 +80,7 @@ class QPDFCryptoProvider
std::shared_ptr<QPDFCryptoImpl> std::shared_ptr<QPDFCryptoImpl>
getImpl_internal(std::string const& name) const; getImpl_internal(std::string const& name) const;
template<typename T> template <typename T>
void registerImpl_internal(std::string const& name); void registerImpl_internal(std::string const& name);
void setDefaultProvider_internal(std::string const& name); void setDefaultProvider_internal(std::string const& name);
@ -100,7 +97,7 @@ class QPDFCryptoProvider
Members(Members const&) = delete; Members(Members const&) = delete;
Members& operator=(Members const&) = delete; Members& operator=(Members const&) = delete;
typedef std::function<std::shared_ptr<QPDFCryptoImpl> ()> provider_fn; typedef std::function<std::shared_ptr<QPDFCryptoImpl>()> provider_fn;
std::string default_provider; std::string default_provider;
std::map<std::string, provider_fn> providers; std::map<std::string, provider_fn> providers;
}; };

View File

@ -49,12 +49,14 @@ class QPDFDocumentHelper
{ {
} }
QPDF_DLL QPDF_DLL
QPDF& getQPDF() QPDF&
getQPDF()
{ {
return this->qpdf; return this->qpdf;
} }
QPDF_DLL QPDF_DLL
QPDF const& getQPDF() const QPDF const&
getQPDF() const
{ {
return this->qpdf; return this->qpdf;
} }

View File

@ -24,13 +24,13 @@
#include <qpdf/QPDFDocumentHelper.hh> #include <qpdf/QPDFDocumentHelper.hh>
#include <qpdf/QPDF.hh>
#include <qpdf/QPDFNameTreeObjectHelper.hh>
#include <qpdf/QPDFFileSpecObjectHelper.hh>
#include <qpdf/DLL.h> #include <qpdf/DLL.h>
#include <qpdf/QPDF.hh>
#include <qpdf/QPDFFileSpecObjectHelper.hh>
#include <qpdf/QPDFNameTreeObjectHelper.hh>
#include <memory>
#include <map> #include <map>
#include <memory>
// This class provides a higher level interface around document-level // This class provides a higher level interface around document-level
// file attachments, also known as embedded files. These are discussed // file attachments, also known as embedded files. These are discussed
@ -48,8 +48,8 @@ class QPDFEmbeddedFileDocumentHelper: public QPDFDocumentHelper
bool hasEmbeddedFiles() const; bool hasEmbeddedFiles() const;
QPDF_DLL QPDF_DLL
std::map<std::string, std::map<std::string, std::shared_ptr<QPDFFileSpecObjectHelper>>
std::shared_ptr<QPDFFileSpecObjectHelper>> getEmbeddedFiles(); getEmbeddedFiles();
// If an embedded file with the given name exists, return a // If an embedded file with the given name exists, return a
// (shared) pointer to it. Otherwise, return nullptr. // (shared) pointer to it. Otherwise, return nullptr.

View File

@ -22,22 +22,23 @@
#ifndef QPDFEXC_HH #ifndef QPDFEXC_HH
#define QPDFEXC_HH #define QPDFEXC_HH
#include <qpdf/Constants.h>
#include <qpdf/DLL.h> #include <qpdf/DLL.h>
#include <qpdf/Types.h> #include <qpdf/Types.h>
#include <qpdf/Constants.h>
#include <string>
#include <stdexcept> #include <stdexcept>
#include <string>
class QPDF_DLL_CLASS QPDFExc: public std::runtime_error class QPDF_DLL_CLASS QPDFExc: public std::runtime_error
{ {
public: public:
QPDF_DLL QPDF_DLL
QPDFExc(qpdf_error_code_e error_code, QPDFExc(
std::string const& filename, qpdf_error_code_e error_code,
std::string const& object, std::string const& filename,
qpdf_offset_t offset, std::string const& object,
std::string const& message); qpdf_offset_t offset,
std::string const& message);
QPDF_DLL QPDF_DLL
virtual ~QPDFExc() noexcept virtual ~QPDFExc() noexcept
{ {
@ -65,10 +66,11 @@ class QPDF_DLL_CLASS QPDFExc: public std::runtime_error
std::string const& getMessageDetail() const; std::string const& getMessageDetail() const;
private: private:
static std::string createWhat(std::string const& filename, static std::string createWhat(
std::string const& object, std::string const& filename,
qpdf_offset_t offset, std::string const& object,
std::string const& message); qpdf_offset_t offset,
std::string const& message);
// This class does not use the Members pattern to avoid needless // This class does not use the Members pattern to avoid needless
// memory allocations during exception handling. // memory allocations during exception handling.

View File

@ -26,8 +26,8 @@
#include <qpdf/DLL.h> #include <qpdf/DLL.h>
#include <qpdf/QPDFObjectHandle.hh>
#include <qpdf/QPDFEFStreamObjectHelper.hh> #include <qpdf/QPDFEFStreamObjectHelper.hh>
#include <qpdf/QPDFObjectHandle.hh>
// This class provides a higher level interface around File // This class provides a higher level interface around File
// Specification dictionaries, which are discussed in section 7.11 of // Specification dictionaries, which are discussed in section 7.11 of
@ -77,22 +77,16 @@ class QPDFFileSpecObjectHelper: public QPDFObjectHelper
// filename, and attach the contents of the specified file as data // filename, and attach the contents of the specified file as data
// in an embedded file stream. // in an embedded file stream.
QPDF_DLL QPDF_DLL
static static QPDFFileSpecObjectHelper createFileSpec(
QPDFFileSpecObjectHelper createFileSpec( QPDF& qpdf, std::string const& filename, std::string const& fullpath);
QPDF& qpdf,
std::string const& filename,
std::string const& fullpath);
// Create a new filespec as an indirect object with the given // Create a new filespec as an indirect object with the given
// unicode filename and embedded file stream. The file name will // unicode filename and embedded file stream. The file name will
// be used as both /UF and /F. If you need to override, call // be used as both /UF and /F. If you need to override, call
// setFilename. // setFilename.
QPDF_DLL QPDF_DLL
static static QPDFFileSpecObjectHelper createFileSpec(
QPDFFileSpecObjectHelper createFileSpec( QPDF& qpdf, std::string const& filename, QPDFEFStreamObjectHelper);
QPDF& qpdf,
std::string const& filename,
QPDFEFStreamObjectHelper);
QPDF_DLL QPDF_DLL
QPDFFileSpecObjectHelper& setDescription(std::string const&); QPDFFileSpecObjectHelper& setDescription(std::string const&);
@ -103,8 +97,7 @@ class QPDFFileSpecObjectHelper: public QPDFObjectHelper
// might happen to have. // might happen to have.
QPDF_DLL QPDF_DLL
QPDFFileSpecObjectHelper& setFilename( QPDFFileSpecObjectHelper& setFilename(
std::string const& unicode_name, std::string const& unicode_name, std::string const& compat_name = "");
std::string const& compat_name = "");
private: private:
class Members class Members

View File

@ -185,8 +185,8 @@ class QPDFFormFieldObjectHelper: public QPDFObjectHelper
// of a field, use QPDFAcroFormDocumentHelper::setFormFieldName // of a field, use QPDFAcroFormDocumentHelper::setFormFieldName
// instead. // instead.
QPDF_DLL QPDF_DLL
void setFieldAttribute(std::string const& key, void
std::string const& utf8_value); setFieldAttribute(std::string const& key, std::string const& utf8_value);
// Set /V (field value) to the given value. If need_appearances is // Set /V (field value) to the given value. If need_appearances is
// true and the field type is either /Tx (text) or /Ch (choice), // true and the field type is either /Tx (text) or /Ch (choice),

View File

@ -22,22 +22,21 @@
#ifndef QPDFJOB_HH #ifndef QPDFJOB_HH
#define QPDFJOB_HH #define QPDFJOB_HH
#include <qpdf/DLL.h>
#include <qpdf/Constants.h> #include <qpdf/Constants.h>
#include <qpdf/DLL.h>
#include <qpdf/PDFVersion.hh>
#include <qpdf/QPDF.hh> #include <qpdf/QPDF.hh>
#include <qpdf/QPDFPageObjectHelper.hh> #include <qpdf/QPDFPageObjectHelper.hh>
#include <qpdf/PDFVersion.hh>
#include <memory>
#include <string>
#include <list>
#include <vector>
#include <set>
#include <map>
#include <iostream>
#include <functional> #include <functional>
#include <iostream>
#include <list>
#include <map>
#include <memory> #include <memory>
#include <set>
#include <stdexcept> #include <stdexcept>
#include <string>
#include <vector>
class QPDFWriter; class QPDFWriter;
@ -79,8 +78,8 @@ class QPDFJob
// about converting arguments to UTF-8. This method will mutate // about converting arguments to UTF-8. This method will mutate
// arguments that are passed to it. // arguments that are passed to it.
QPDF_DLL QPDF_DLL
void initializeFromArgv(char const* const argv[], void initializeFromArgv(
char const* progname_env = nullptr); char const* const argv[], char const* progname_env = nullptr);
// Initialize a QPDFJob from json. Passing partial = true prevents // Initialize a QPDFJob from json. Passing partial = true prevents
// this method from doing the final checks (calling // this method from doing the final checks (calling
@ -155,9 +154,10 @@ class QPDFJob
struct PageSpec struct PageSpec
{ {
PageSpec(std::string const& filename, PageSpec(
char const* password, std::string const& filename,
std::string const& range); char const* password,
std::string const& range);
std::string filename; std::string filename;
std::shared_ptr<char> password; std::shared_ptr<char> password;
@ -203,13 +203,14 @@ class QPDFJob
{ {
friend class QPDFJob; friend class QPDFJob;
friend class Config; friend class Config;
public: public:
QPDF_DLL QPDF_DLL
Config* endAddAttachment(); Config* endAddAttachment();
QPDF_DLL QPDF_DLL
AttConfig* file(std::string const& parameter); AttConfig* file(std::string const& parameter);
# include <qpdf/auto_job_c_att.hh> #include <qpdf/auto_job_c_att.hh>
private: private:
AttConfig(Config*); AttConfig(Config*);
@ -223,13 +224,14 @@ class QPDFJob
{ {
friend class QPDFJob; friend class QPDFJob;
friend class Config; friend class Config;
public: public:
QPDF_DLL QPDF_DLL
Config* endCopyAttachmentsFrom(); Config* endCopyAttachmentsFrom();
QPDF_DLL QPDF_DLL
CopyAttConfig* file(std::string const& parameter); CopyAttConfig* file(std::string const& parameter);
# include <qpdf/auto_job_c_copy_att.hh> #include <qpdf/auto_job_c_copy_att.hh>
private: private:
CopyAttConfig(Config*); CopyAttConfig(Config*);
@ -243,15 +245,17 @@ class QPDFJob
{ {
friend class QPDFJob; friend class QPDFJob;
friend class Config; friend class Config;
public: public:
QPDF_DLL QPDF_DLL
Config* endPages(); Config* endPages();
QPDF_DLL QPDF_DLL
PagesConfig* pageSpec(std::string const& filename, PagesConfig* pageSpec(
std::string const& range, std::string const& filename,
char const* password = nullptr); std::string const& range,
char const* password = nullptr);
# include <qpdf/auto_job_c_pages.hh> #include <qpdf/auto_job_c_pages.hh>
private: private:
PagesConfig(Config*); PagesConfig(Config*);
@ -264,13 +268,14 @@ class QPDFJob
{ {
friend class QPDFJob; friend class QPDFJob;
friend class Config; friend class Config;
public: public:
QPDF_DLL QPDF_DLL
Config* endUnderlayOverlay(); Config* endUnderlayOverlay();
QPDF_DLL QPDF_DLL
UOConfig* file(std::string const& parameter); UOConfig* file(std::string const& parameter);
# include <qpdf/auto_job_c_uo.hh> #include <qpdf/auto_job_c_uo.hh>
private: private:
UOConfig(Config*); UOConfig(Config*);
@ -283,13 +288,14 @@ class QPDFJob
{ {
friend class QPDFJob; friend class QPDFJob;
friend class Config; friend class Config;
public: public:
QPDF_DLL QPDF_DLL
Config* endEncrypt(); Config* endEncrypt();
QPDF_DLL QPDF_DLL
EncConfig* file(std::string const& parameter); EncConfig* file(std::string const& parameter);
# include <qpdf/auto_job_c_enc.hh> #include <qpdf/auto_job_c_enc.hh>
private: private:
EncConfig(Config*); EncConfig(Config*);
@ -301,6 +307,7 @@ class QPDFJob
class Config class Config
{ {
friend class QPDFJob; friend class QPDFJob;
public: public:
// Proxy to QPDFJob::checkConfiguration() // Proxy to QPDFJob::checkConfiguration()
QPDF_DLL QPDF_DLL
@ -331,7 +338,7 @@ class QPDFJob
std::string const& user_password, std::string const& user_password,
std::string const& owner_password); std::string const& owner_password);
# include <qpdf/auto_job_c_main.hh> #include <qpdf/auto_job_c_main.hh>
private: private:
Config() = delete; Config() = delete;
@ -444,32 +451,37 @@ class QPDFJob
// Basic file processing // Basic file processing
std::shared_ptr<QPDF> processFile( std::shared_ptr<QPDF> processFile(
char const* filename, char const* password, char const* filename, char const* password, bool used_for_input);
bool used_for_input);
std::shared_ptr<QPDF> processInputSource( std::shared_ptr<QPDF> processInputSource(
PointerHolder<InputSource> is, char const* password, PointerHolder<InputSource> is,
char const* password,
bool used_for_input); bool used_for_input);
std::shared_ptr<QPDF> doProcess( std::shared_ptr<QPDF> doProcess(
std::function<void(QPDF*, char const*)> fn, std::function<void(QPDF*, char const*)> fn,
char const* password, bool empty, bool used_for_input); char const* password,
bool empty,
bool used_for_input);
std::shared_ptr<QPDF> doProcessOnce( std::shared_ptr<QPDF> doProcessOnce(
std::function<void(QPDF*, char const*)> fn, std::function<void(QPDF*, char const*)> fn,
char const* password, bool empty, bool used_for_input); char const* password,
bool empty,
bool used_for_input);
// Transformations // Transformations
void setQPDFOptions(QPDF& pdf); void setQPDFOptions(QPDF& pdf);
void handlePageSpecs( void handlePageSpecs(
QPDF& pdf, bool& warnings, QPDF& pdf,
bool& warnings,
std::vector<std::shared_ptr<QPDF>>& page_heap); std::vector<std::shared_ptr<QPDF>>& page_heap);
bool shouldRemoveUnreferencedResources(QPDF& pdf); bool shouldRemoveUnreferencedResources(QPDF& pdf);
void handleRotations(QPDF& pdf); void handleRotations(QPDF& pdf);
void getUOPagenos(UnderOverlay& uo, void
std::map<int, std::vector<int> >& pagenos); getUOPagenos(UnderOverlay& uo, std::map<int, std::vector<int>>& pagenos);
void handleUnderOverlay(QPDF& pdf); void handleUnderOverlay(QPDF& pdf);
void doUnderOverlayForPage( void doUnderOverlayForPage(
QPDF& pdf, QPDF& pdf,
UnderOverlay& uo, UnderOverlay& uo,
std::map<int, std::vector<int> >& pagenos, std::map<int, std::vector<int>>& pagenos,
size_t page_idx, size_t page_idx,
std::map<int, QPDFObjectHandle>& fo, std::map<int, QPDFObjectHandle>& fo,
std::vector<QPDFPageObjectHelper>& pages, std::vector<QPDFPageObjectHelper>& pages,

View File

@ -22,8 +22,8 @@
#ifndef QPDFMATRIX_HH #ifndef QPDFMATRIX_HH
#define QPDFMATRIX_HH #define QPDFMATRIX_HH
#include <qpdf/QPDFObjectHandle.hh>
#include <qpdf/DLL.h> #include <qpdf/DLL.h>
#include <qpdf/QPDFObjectHandle.hh>
#include <string> #include <string>
// This class represents a PDF transformation matrix using a tuple // This class represents a PDF transformation matrix using a tuple
@ -41,8 +41,7 @@ class QPDFMatrix
QPDF_DLL QPDF_DLL
QPDFMatrix(); QPDFMatrix();
QPDF_DLL QPDF_DLL
QPDFMatrix(double a, double b, double c, QPDFMatrix(double a, double b, double c, double d, double e, double f);
double d, double e, double f);
QPDF_DLL QPDF_DLL
QPDFMatrix(QPDFObjectHandle::Matrix const&); QPDFMatrix(QPDFObjectHandle::Matrix const&);
@ -83,21 +82,22 @@ class QPDFMatrix
// bounds the polygon resulting from transforming the four // bounds the polygon resulting from transforming the four
// corners. // corners.
QPDF_DLL QPDF_DLL
QPDFObjectHandle::Rectangle transformRectangle( QPDFObjectHandle::Rectangle
QPDFObjectHandle::Rectangle r) const; transformRectangle(QPDFObjectHandle::Rectangle r) const;
// ABI: delete non-const version // ABI: delete non-const version
QPDF_DLL QPDF_DLL
QPDFObjectHandle::Rectangle transformRectangle( QPDFObjectHandle::Rectangle
QPDFObjectHandle::Rectangle r); transformRectangle(QPDFObjectHandle::Rectangle r);
// operator== tests for exact equality, not considering deltas for // operator== tests for exact equality, not considering deltas for
// floating point. // floating point.
QPDF_DLL QPDF_DLL
bool operator==(QPDFMatrix const& rhs) const; bool operator==(QPDFMatrix const& rhs) const;
QPDF_DLL QPDF_DLL
bool operator!=(QPDFMatrix const& rhs) const bool
operator!=(QPDFMatrix const& rhs) const
{ {
return ! operator==(rhs); return !operator==(rhs);
} }
double a; double a;

View File

@ -22,11 +22,11 @@
#ifndef QPDFNAMETREEOBJECTHELPER_HH #ifndef QPDFNAMETREEOBJECTHELPER_HH
#define QPDFNAMETREEOBJECTHELPER_HH #define QPDFNAMETREEOBJECTHELPER_HH
#include <qpdf/QPDFObjectHelper.hh>
#include <qpdf/QPDFObjGen.hh> #include <qpdf/QPDFObjGen.hh>
#include <qpdf/QPDFObjectHelper.hh>
#include <iterator>
#include <map> #include <map>
#include <memory> #include <memory>
#include <iterator>
#include <qpdf/DLL.h> #include <qpdf/DLL.h>
@ -48,16 +48,14 @@ class QPDFNameTreeObjectHelper: public QPDFObjectHelper
// The qpdf object is required so that this class can issue // The qpdf object is required so that this class can issue
// warnings, attempt repairs, and add indirect objects. // warnings, attempt repairs, and add indirect objects.
QPDF_DLL QPDF_DLL
QPDFNameTreeObjectHelper(QPDFObjectHandle, QPDF&, QPDFNameTreeObjectHelper(QPDFObjectHandle, QPDF&, bool auto_repair = true);
bool auto_repair = true);
// ABI: Legacy Constructor will be removed in QPDF 11. A // ABI: Legacy Constructor will be removed in QPDF 11. A
// QPDFNameTreeObjectHelper constructed in this way can't be // QPDFNameTreeObjectHelper constructed in this way can't be
// modified or repaired and will silently ignore problems in the // modified or repaired and will silently ignore problems in the
// structure. // structure.
[[deprecated("use constructor that takes QPDF&")]] [[deprecated("use constructor that takes QPDF&")]] QPDF_DLL
QPDF_DLL QPDFNameTreeObjectHelper(QPDFObjectHandle);
QPDFNameTreeObjectHelper(QPDFObjectHandle);
// Create an empty name tree // Create an empty name tree
QPDF_DLL QPDF_DLL
@ -80,6 +78,7 @@ class QPDFNameTreeObjectHelper: public QPDFObjectHelper
class iterator class iterator
{ {
friend class QPDFNameTreeObjectHelper; friend class QPDFNameTreeObjectHelper;
public: public:
typedef std::pair<std::string, QPDFObjectHandle> T; typedef std::pair<std::string, QPDFObjectHandle> T;
using iterator_category = std::bidirectional_iterator_tag; using iterator_category = std::bidirectional_iterator_tag;
@ -94,7 +93,8 @@ class QPDFNameTreeObjectHelper: public QPDFObjectHelper
QPDF_DLL QPDF_DLL
iterator& operator++(); iterator& operator++();
QPDF_DLL QPDF_DLL
iterator operator++(int) iterator
operator++(int)
{ {
iterator t = *this; iterator t = *this;
++(*this); ++(*this);
@ -103,7 +103,8 @@ class QPDFNameTreeObjectHelper: public QPDFObjectHelper
QPDF_DLL QPDF_DLL
iterator& operator--(); iterator& operator--();
QPDF_DLL QPDF_DLL
iterator operator--(int) iterator
operator--(int)
{ {
iterator t = *this; iterator t = *this;
--(*this); --(*this);
@ -116,9 +117,10 @@ class QPDFNameTreeObjectHelper: public QPDFObjectHelper
QPDF_DLL QPDF_DLL
bool operator==(iterator const& other) const; bool operator==(iterator const& other) const;
QPDF_DLL QPDF_DLL
bool operator!=(iterator const& other) const bool
operator!=(iterator const& other) const
{ {
return ! operator==(other); return !operator==(other);
} }
// DANGER: this method can create inconsistent trees if not // DANGER: this method can create inconsistent trees if not
@ -162,8 +164,8 @@ class QPDFNameTreeObjectHelper: public QPDFObjectHelper
// Find the entry with the given key. If return_prev_if_not_found // Find the entry with the given key. If return_prev_if_not_found
// is true and the item is not found, return the next lower item. // is true and the item is not found, return the next lower item.
QPDF_DLL QPDF_DLL
iterator find(std::string const& key, iterator
bool return_prev_if_not_found = false); find(std::string const& key, bool return_prev_if_not_found = false);
// Insert a new item. If the key already exists, it is replaced. // Insert a new item. If the key already exists, it is replaced.
QPDF_DLL QPDF_DLL

View File

@ -22,8 +22,8 @@
#ifndef QPDFNUMBERTREEOBJECTHELPER_HH #ifndef QPDFNUMBERTREEOBJECTHELPER_HH
#define QPDFNUMBERTREEOBJECTHELPER_HH #define QPDFNUMBERTREEOBJECTHELPER_HH
#include <qpdf/QPDFObjectHelper.hh>
#include <qpdf/QPDFObjGen.hh> #include <qpdf/QPDFObjGen.hh>
#include <qpdf/QPDFObjectHelper.hh>
#include <map> #include <map>
#include <memory> #include <memory>
@ -45,16 +45,15 @@ class QPDFNumberTreeObjectHelper: public QPDFObjectHelper
// The qpdf object is required so that this class can issue // The qpdf object is required so that this class can issue
// warnings, attempt repairs, and add indirect objects. // warnings, attempt repairs, and add indirect objects.
QPDF_DLL QPDF_DLL
QPDFNumberTreeObjectHelper(QPDFObjectHandle, QPDF&, QPDFNumberTreeObjectHelper(
bool auto_repair = true); QPDFObjectHandle, QPDF&, bool auto_repair = true);
// ABI: Legacy Constructor will be removed in QPDF 11. A // ABI: Legacy Constructor will be removed in QPDF 11. A
// QPDFNumberTreeObjectHelper constructed in this way can't be // QPDFNumberTreeObjectHelper constructed in this way can't be
// modified or repaired and will silently ignore problems in the // modified or repaired and will silently ignore problems in the
// structure. // structure.
[[deprecated("use constructor that takes QPDF&")]] [[deprecated("use constructor that takes QPDF&")]] QPDF_DLL
QPDF_DLL QPDFNumberTreeObjectHelper(QPDFObjectHandle);
QPDFNumberTreeObjectHelper(QPDFObjectHandle);
// ABI: = default // ABI: = default
QPDF_DLL QPDF_DLL
@ -93,12 +92,13 @@ class QPDFNumberTreeObjectHelper: public QPDFObjectHelper
// oh to the value with index 3, and set offset to 2 (5 - 3). See // oh to the value with index 3, and set offset to 2 (5 - 3). See
// also find(). // also find().
QPDF_DLL QPDF_DLL
bool findObjectAtOrBelow(numtree_number idx, QPDFObjectHandle& oh, bool findObjectAtOrBelow(
numtree_number& offset); numtree_number idx, QPDFObjectHandle& oh, numtree_number& offset);
class iterator class iterator
{ {
friend class QPDFNumberTreeObjectHelper; friend class QPDFNumberTreeObjectHelper;
public: public:
typedef std::pair<numtree_number, QPDFObjectHandle> T; typedef std::pair<numtree_number, QPDFObjectHandle> T;
using iterator_category = std::bidirectional_iterator_tag; using iterator_category = std::bidirectional_iterator_tag;
@ -113,7 +113,8 @@ class QPDFNumberTreeObjectHelper: public QPDFObjectHelper
QPDF_DLL QPDF_DLL
iterator& operator++(); iterator& operator++();
QPDF_DLL QPDF_DLL
iterator operator++(int) iterator
operator++(int)
{ {
iterator t = *this; iterator t = *this;
++(*this); ++(*this);
@ -122,7 +123,8 @@ class QPDFNumberTreeObjectHelper: public QPDFObjectHelper
QPDF_DLL QPDF_DLL
iterator& operator--(); iterator& operator--();
QPDF_DLL QPDF_DLL
iterator operator--(int) iterator
operator--(int)
{ {
iterator t = *this; iterator t = *this;
--(*this); --(*this);
@ -135,9 +137,10 @@ class QPDFNumberTreeObjectHelper: public QPDFObjectHelper
QPDF_DLL QPDF_DLL
bool operator==(iterator const& other) const; bool operator==(iterator const& other) const;
QPDF_DLL QPDF_DLL
bool operator!=(iterator const& other) const bool
operator!=(iterator const& other) const
{ {
return ! operator==(other); return !operator==(other);
} }
// DANGER: this method can create inconsistent trees if not // DANGER: this method can create inconsistent trees if not

View File

@ -22,10 +22,10 @@
#ifndef QPDFOBJECT_HH #ifndef QPDFOBJECT_HH
#define QPDFOBJECT_HH #define QPDFOBJECT_HH
#include <qpdf/DLL.h>
#include <qpdf/Types.h>
#include <qpdf/JSON.hh>
#include <qpdf/Constants.h> #include <qpdf/Constants.h>
#include <qpdf/DLL.h>
#include <qpdf/JSON.hh>
#include <qpdf/Types.h>
#include <string> #include <string>
@ -62,7 +62,9 @@ class QPDF_DLL_CLASS QPDFObject
static constexpr object_type_e ot_operator = ::ot_operator; static constexpr object_type_e ot_operator = ::ot_operator;
static constexpr object_type_e ot_inlineimage = ::ot_inlineimage; static constexpr object_type_e ot_inlineimage = ::ot_inlineimage;
virtual ~QPDFObject() {} virtual ~QPDFObject()
{
}
virtual std::string unparse() = 0; virtual std::string unparse() = 0;
virtual JSON getJSON() = 0; virtual JSON getJSON() = 0;
@ -78,11 +80,12 @@ class QPDF_DLL_CLASS QPDFObject
{ {
friend class QPDF; friend class QPDF;
friend class QPDFObjectHandle; friend class QPDFObjectHandle;
private: private:
static void releaseResolved(QPDFObject* o) static void
releaseResolved(QPDFObject* o)
{ {
if (o) if (o) {
{
o->releaseResolved(); o->releaseResolved();
} }
} }
@ -97,7 +100,10 @@ class QPDF_DLL_CLASS QPDFObject
qpdf_offset_t getParsedOffset(); qpdf_offset_t getParsedOffset();
protected: protected:
virtual void releaseResolved() {} virtual void
releaseResolved()
{
}
private: private:
QPDFObject(QPDFObject const&) = delete; QPDFObject(QPDFObject const&) = delete;

View File

@ -22,21 +22,21 @@
#ifndef QPDFOBJECTHANDLE_HH #ifndef QPDFOBJECTHANDLE_HH
#define QPDFOBJECTHANDLE_HH #define QPDFOBJECTHANDLE_HH
#include <qpdf/Constants.h>
#include <qpdf/DLL.h> #include <qpdf/DLL.h>
#include <qpdf/Types.h> #include <qpdf/Types.h>
#include <qpdf/Constants.h>
#include <functional>
#include <map>
#include <memory>
#include <set>
#include <string> #include <string>
#include <vector> #include <vector>
#include <set>
#include <map>
#include <functional>
#include <memory>
#include <qpdf/QPDFObjGen.hh>
#include <qpdf/PointerHolder.hh>
#include <qpdf/Buffer.hh> #include <qpdf/Buffer.hh>
#include <qpdf/InputSource.hh> #include <qpdf/InputSource.hh>
#include <qpdf/PointerHolder.hh>
#include <qpdf/QPDFObjGen.hh>
#include <qpdf/QPDFTokenizer.hh> #include <qpdf/QPDFTokenizer.hh>
#include <qpdf/QPDFObject.hh> #include <qpdf/QPDFObject.hh>
@ -117,12 +117,15 @@ class QPDFObjectHandle
// version of the method, which should also return a boolean // version of the method, which should also return a boolean
// indicating whether it ran without errors. // indicating whether it ran without errors.
QPDF_DLL QPDF_DLL
virtual void provideStreamData(int objid, int generation, virtual void
Pipeline* pipeline); provideStreamData(int objid, int generation, Pipeline* pipeline);
QPDF_DLL QPDF_DLL
virtual bool provideStreamData( virtual bool provideStreamData(
int objid, int generation, Pipeline* pipeline, int objid,
bool suppress_warnings, bool will_retry); int generation,
Pipeline* pipeline,
bool suppress_warnings,
bool will_retry);
QPDF_DLL QPDF_DLL
bool supportsRetry(); bool supportsRetry();
@ -183,8 +186,10 @@ class QPDFObjectHandle
class PipelineAccessor class PipelineAccessor
{ {
friend class Pl_QPDFTokenizer; friend class Pl_QPDFTokenizer;
private: private:
static void setPipeline(TokenFilter* f, Pipeline* p) static void
setPipeline(TokenFilter* f, Pipeline* p)
{ {
f->setPipeline(p); f->setPipeline(p);
} }
@ -230,8 +235,8 @@ class QPDFObjectHandle
QPDF_DLL QPDF_DLL
virtual void handleObject(QPDFObjectHandle); virtual void handleObject(QPDFObjectHandle);
QPDF_DLL QPDF_DLL
virtual void handleObject( virtual void
QPDFObjectHandle, size_t offset, size_t length); handleObject(QPDFObjectHandle, size_t offset, size_t length);
virtual void handleEOF() = 0; virtual void handleEOF() = 0;
@ -261,8 +266,7 @@ class QPDFObjectHandle
ury(0.0) ury(0.0)
{ {
} }
Rectangle(double llx, double lly, Rectangle(double llx, double lly, double urx, double ury) :
double urx, double ury) :
llx(llx), llx(llx),
lly(lly), lly(lly),
urx(urx), urx(urx),
@ -292,8 +296,7 @@ class QPDFObjectHandle
f(0.0) f(0.0)
{ {
} }
Matrix(double a, double b, double c, Matrix(double a, double b, double c, double d, double e, double f) :
double d, double e, double f) :
a(a), a(a),
b(b), b(b),
c(c), c(c),
@ -316,8 +319,7 @@ class QPDFObjectHandle
QPDF_DLL QPDF_DLL
QPDFObjectHandle(QPDFObjectHandle const&) = default; QPDFObjectHandle(QPDFObjectHandle const&) = default;
QPDF_DLL QPDF_DLL
QPDFObjectHandle& QPDFObjectHandle& operator=(QPDFObjectHandle const&) = default;
operator=(QPDFObjectHandle const&) = default;
QPDF_DLL QPDF_DLL
bool isInitialized() const; bool isInitialized() const;
@ -381,14 +383,14 @@ class QPDFObjectHandle
// True if the object is a dictionary of the specified type and // True if the object is a dictionary of the specified type and
// subtype, if any. // subtype, if any.
QPDF_DLL QPDF_DLL
bool isDictionaryOfType(std::string const& type, bool isDictionaryOfType(
std::string const& subtype = ""); std::string const& type, std::string const& subtype = "");
// True if the object is a stream of the specified type and // True if the object is a stream of the specified type and
// subtype, if any. // subtype, if any.
QPDF_DLL QPDF_DLL
bool isStreamOfType(std::string const& type, bool
std::string const& subtype = ""); isStreamOfType(std::string const& type, std::string const& subtype = "");
// Public factory methods // Public factory methods
@ -406,8 +408,9 @@ class QPDFObjectHandle
// in the message of any QPDFExc exception thrown for invalid // in the message of any QPDFExc exception thrown for invalid
// syntax. See also the global `operator ""_qpdf` defined below. // syntax. See also the global `operator ""_qpdf` defined below.
QPDF_DLL QPDF_DLL
static QPDFObjectHandle parse(std::string const& object_str, static QPDFObjectHandle parse(
std::string const& object_description = ""); std::string const& object_str,
std::string const& object_description = "");
// Construct an object of any type from a string representation of // Construct an object of any type from a string representation of
// the object. Indirect object syntax (obj gen R) is allowed and // the object. Indirect object syntax (obj gen R) is allowed and
@ -419,9 +422,10 @@ class QPDFObjectHandle
// object, which will just be the first number and will report // object, which will just be the first number and will report
// that there is trailing data at the end of the string. // that there is trailing data at the end of the string.
QPDF_DLL QPDF_DLL
static QPDFObjectHandle parse(QPDF* context, static QPDFObjectHandle parse(
std::string const& object_str, QPDF* context,
std::string const& object_description = ""); std::string const& object_str,
std::string const& object_description = "");
// Construct an object as above by reading from the given // Construct an object as above by reading from the given
// InputSource at its current position and using the tokenizer you // InputSource at its current position and using the tokenizer you
@ -429,11 +433,13 @@ class QPDFObjectHandle
// This method is intended to be called by QPDF for parsing // This method is intended to be called by QPDF for parsing
// objects that are ready from the object's input stream. // objects that are ready from the object's input stream.
QPDF_DLL QPDF_DLL
static QPDFObjectHandle parse(PointerHolder<InputSource> input, static QPDFObjectHandle parse(
std::string const& object_description, PointerHolder<InputSource> input,
QPDFTokenizer&, bool& empty, std::string const& object_description,
StringDecrypter* decrypter, QPDFTokenizer&,
QPDF* context); bool& empty,
StringDecrypter* decrypter,
QPDF* context);
// Return the offset where the object was found when parsed. A // Return the offset where the object was found when parsed. A
// negative value means that the object was created without // negative value means that the object was created without
@ -449,8 +455,8 @@ class QPDFObjectHandle
// error messages will also be more useful because the page object // error messages will also be more useful because the page object
// information will be known. // information will be known.
QPDF_DLL QPDF_DLL
static void parseContentStream(QPDFObjectHandle stream_or_array, static void parseContentStream(
ParserCallbacks* callbacks); QPDFObjectHandle stream_or_array, ParserCallbacks* callbacks);
// When called on a stream or stream array that is some page's // When called on a stream or stream array that is some page's
// content streams, do the same as pipePageContents. This method // content streams, do the same as pipePageContents. This method
@ -469,8 +475,10 @@ class QPDFObjectHandle
// Pl_Concatenate and then call manualFinish() on the // Pl_Concatenate and then call manualFinish() on the
// Pl_Concatenate pipeline at the end. // Pl_Concatenate pipeline at the end.
QPDF_DLL QPDF_DLL
void pipeContentStreams(Pipeline* p, std::string const& description, void pipeContentStreams(
std::string& all_description); Pipeline* p,
std::string const& description,
std::string& all_description);
// As of qpdf 8, it is possible to add custom token filters to a // As of qpdf 8, it is possible to add custom token filters to a
// stream. The tokenized stream data is passed through the token // stream. The tokenized stream data is passed through the token
@ -525,8 +533,8 @@ class QPDFObjectHandle
// ABI: combine with other newReal by adding trim_trailing_zeroes // ABI: combine with other newReal by adding trim_trailing_zeroes
// above as an optional parameter with a default of true. // above as an optional parameter with a default of true.
QPDF_DLL QPDF_DLL
static QPDFObjectHandle newReal(double value, int decimal_places, static QPDFObjectHandle
bool trim_trailing_zeroes); newReal(double value, int decimal_places, bool trim_trailing_zeroes);
// Note about name objects: qpdf's internal representation of a // Note about name objects: qpdf's internal representation of a
// PDF name is a sequence of bytes, excluding the NUL character, // PDF name is a sequence of bytes, excluding the NUL character,
// and starting with a slash. Name objects as represented in the // and starting with a slash. Name objects as represented in the
@ -562,8 +570,8 @@ class QPDFObjectHandle
QPDF_DLL QPDF_DLL
static QPDFObjectHandle newArray(); static QPDFObjectHandle newArray();
QPDF_DLL QPDF_DLL
static QPDFObjectHandle newArray( static QPDFObjectHandle
std::vector<QPDFObjectHandle> const& items); newArray(std::vector<QPDFObjectHandle> const& items);
QPDF_DLL QPDF_DLL
static QPDFObjectHandle newArray(Rectangle const&); static QPDFObjectHandle newArray(Rectangle const&);
QPDF_DLL QPDF_DLL
@ -573,8 +581,8 @@ class QPDFObjectHandle
QPDF_DLL QPDF_DLL
static QPDFObjectHandle newDictionary(); static QPDFObjectHandle newDictionary();
QPDF_DLL QPDF_DLL
static QPDFObjectHandle newDictionary( static QPDFObjectHandle
std::map<std::string, QPDFObjectHandle> const& items); newDictionary(std::map<std::string, QPDFObjectHandle> const& items);
// Create an array from a rectangle. Equivalent to the rectangle // Create an array from a rectangle. Equivalent to the rectangle
// form of newArray. // form of newArray.
@ -646,8 +654,8 @@ class QPDFObjectHandle
// with proper context in some cases where it would otherwise // with proper context in some cases where it would otherwise
// raise exceptions. // raise exceptions.
QPDF_DLL QPDF_DLL
void setObjectDescription(QPDF* owning_qpdf, void setObjectDescription(
std::string const& object_description); QPDF* owning_qpdf, std::string const& object_description);
QPDF_DLL QPDF_DLL
bool hasObjectDescription(); bool hasObjectDescription();
@ -959,8 +967,8 @@ class QPDFObjectHandle
// ABI: remove this version and make resource_names default to // ABI: remove this version and make resource_names default to
// nullptr. // nullptr.
QPDF_DLL QPDF_DLL
std::string getUniqueResourceName(std::string const& prefix, std::string
int& min_suffix); getUniqueResourceName(std::string const& prefix, int& min_suffix);
// Return the QPDF object that owns an indirect object. Returns // Return the QPDF object that owns an indirect object. Returns
// null for a direct object. // null for a direct object.
@ -1081,8 +1089,8 @@ class QPDFObjectHandle
// Returns filtered (uncompressed) stream data. Throws an // Returns filtered (uncompressed) stream data. Throws an
// exception if the stream is filtered and we can't decode it. // exception if the stream is filtered and we can't decode it.
QPDF_DLL QPDF_DLL
PointerHolder<Buffer> getStreamData( PointerHolder<Buffer>
qpdf_stream_decode_level_e level = qpdf_dl_generalized); getStreamData(qpdf_stream_decode_level_e level = qpdf_dl_generalized);
// Returns unfiltered (raw) stream data. // Returns unfiltered (raw) stream data.
QPDF_DLL QPDF_DLL
@ -1146,21 +1154,24 @@ class QPDFObjectHandle
// Return value is overall success, even if filtering is not // Return value is overall success, even if filtering is not
// requested. // requested.
QPDF_DLL QPDF_DLL
bool pipeStreamData(Pipeline*, bool* filtering_attempted, bool pipeStreamData(
int encode_flags, Pipeline*,
qpdf_stream_decode_level_e decode_level, bool* filtering_attempted,
bool suppress_warnings = false, int encode_flags,
bool will_retry = false); qpdf_stream_decode_level_e decode_level,
bool suppress_warnings = false,
bool will_retry = false);
// Legacy version. Return value is whether filtering was // Legacy version. Return value is whether filtering was
// attempted. There is no way to determine success if filtering // attempted. There is no way to determine success if filtering
// was not attempted. // was not attempted.
QPDF_DLL QPDF_DLL
bool pipeStreamData(Pipeline*, bool pipeStreamData(
int encode_flags, Pipeline*,
qpdf_stream_decode_level_e decode_level, int encode_flags,
bool suppress_warnings = false, qpdf_stream_decode_level_e decode_level,
bool will_retry = false); bool suppress_warnings = false,
bool will_retry = false);
// Legacy pipeStreamData. This maps to the the flags-based // Legacy pipeStreamData. This maps to the the flags-based
// pipeStreamData as follows: // pipeStreamData as follows:
@ -1170,8 +1181,7 @@ class QPDFObjectHandle
// compress = true -> encode_flags |= qpdf_sf_compress // compress = true -> encode_flags |= qpdf_sf_compress
// Return value is whether filtering was attempted. // Return value is whether filtering was attempted.
QPDF_DLL QPDF_DLL
bool pipeStreamData(Pipeline*, bool filter, bool pipeStreamData(Pipeline*, bool filter, bool normalize, bool compress);
bool normalize, bool compress);
// Replace a stream's dictionary. The new dictionary must be // Replace a stream's dictionary. The new dictionary must be
// consistent with the stream's data. This is most appropriately // consistent with the stream's data. This is most appropriately
@ -1190,18 +1200,20 @@ class QPDFObjectHandle
// interpreted as if the data read from the file, after any // interpreted as if the data read from the file, after any
// decryption filters have been applied, is as presented. // decryption filters have been applied, is as presented.
QPDF_DLL QPDF_DLL
void replaceStreamData(PointerHolder<Buffer> data, void replaceStreamData(
QPDFObjectHandle const& filter, PointerHolder<Buffer> data,
QPDFObjectHandle const& decode_parms); QPDFObjectHandle const& filter,
QPDFObjectHandle const& decode_parms);
// Replace the stream's stream data with the given string. // Replace the stream's stream data with the given string.
// This method will create a copy of the data rather than using // This method will create a copy of the data rather than using
// the user-provided buffer as in the PointerHolder<Buffer> version // the user-provided buffer as in the PointerHolder<Buffer> version
// of replaceStreamData. // of replaceStreamData.
QPDF_DLL QPDF_DLL
void replaceStreamData(std::string const& data, void replaceStreamData(
QPDFObjectHandle const& filter, std::string const& data,
QPDFObjectHandle const& decode_parms); QPDFObjectHandle const& filter,
QPDFObjectHandle const& decode_parms);
// As above, replace this stream's stream data. Instead of // As above, replace this stream's stream data. Instead of
// directly providing a buffer with the stream data, call the // directly providing a buffer with the stream data, call the
@ -1229,9 +1241,10 @@ class QPDFObjectHandle
// parameter. You can also simplify your code by not having to // parameter. You can also simplify your code by not having to
// compute the length in advance. // compute the length in advance.
QPDF_DLL QPDF_DLL
void replaceStreamData(PointerHolder<StreamDataProvider> provider, void replaceStreamData(
QPDFObjectHandle const& filter, PointerHolder<StreamDataProvider> provider,
QPDFObjectHandle const& decode_parms); QPDFObjectHandle const& filter,
QPDFObjectHandle const& decode_parms);
// Starting in qpdf 10.2, you can use C++-11 function objects // Starting in qpdf 10.2, you can use C++-11 function objects
// instead of StreamDataProvider. // instead of StreamDataProvider.
@ -1240,16 +1253,16 @@ class QPDFObjectHandle
// a one-liner to replace stream data with the contents of a file, // a one-liner to replace stream data with the contents of a file,
// pass QUtil::file_provider(filename) as provider. // pass QUtil::file_provider(filename) as provider.
QPDF_DLL QPDF_DLL
void replaceStreamData(std::function<void(Pipeline*)> provider, void replaceStreamData(
QPDFObjectHandle const& filter, std::function<void(Pipeline*)> provider,
QPDFObjectHandle const& decode_parms); QPDFObjectHandle const& filter,
QPDFObjectHandle const& decode_parms);
// The provider should write the stream data to the pipeline, // The provider should write the stream data to the pipeline,
// returning true if it succeeded without errors. // returning true if it succeeded without errors.
QPDF_DLL QPDF_DLL
void replaceStreamData( void replaceStreamData(
std::function<bool(Pipeline*, std::function<bool(Pipeline*, bool suppress_warnings, bool will_retry)>
bool suppress_warnings, provider,
bool will_retry)> provider,
QPDFObjectHandle const& filter, QPDFObjectHandle const& filter,
QPDFObjectHandle const& decode_parms); QPDFObjectHandle const& decode_parms);
@ -1321,8 +1334,8 @@ class QPDFObjectHandle
// descriptions. See comments on setObjectDescription for // descriptions. See comments on setObjectDescription for
// additional details. // additional details.
QPDF_DLL QPDF_DLL
void warnIfPossible(std::string const& warning, void warnIfPossible(
bool throw_if_no_description = false); std::string const& warning, bool throw_if_no_description = false);
// Initializers for objects. This Factory class gives the QPDF // Initializers for objects. This Factory class gives the QPDF
// class specific permission to call factory methods without // class specific permission to call factory methods without
@ -1330,16 +1343,22 @@ class QPDFObjectHandle
class Factory class Factory
{ {
friend class QPDF; friend class QPDF;
private: private:
static QPDFObjectHandle newIndirect(QPDF* qpdf, static QPDFObjectHandle
int objid, int generation) newIndirect(QPDF* qpdf, int objid, int generation)
{ {
return QPDFObjectHandle::newIndirect(qpdf, objid, generation); return QPDFObjectHandle::newIndirect(qpdf, objid, generation);
} }
// object must be dictionary object // object must be dictionary object
static QPDFObjectHandle newStream( static QPDFObjectHandle
QPDF* qpdf, int objid, int generation, newStream(
QPDFObjectHandle stream_dict, qpdf_offset_t offset, size_t length) QPDF* qpdf,
int objid,
int generation,
QPDFObjectHandle stream_dict,
qpdf_offset_t offset,
size_t length)
{ {
return QPDFObjectHandle::newStream( return QPDFObjectHandle::newStream(
qpdf, objid, generation, stream_dict, offset, length); qpdf, objid, generation, stream_dict, offset, length);
@ -1352,8 +1371,10 @@ class QPDFObjectHandle
class ObjAccessor class ObjAccessor
{ {
friend class QPDF; friend class QPDF;
private: private:
static PointerHolder<QPDFObject> getObject(QPDFObjectHandle& o) static PointerHolder<QPDFObject>
getObject(QPDFObjectHandle& o)
{ {
o.dereference(); o.dereference();
return o.obj; return o.obj;
@ -1368,8 +1389,10 @@ class QPDFObjectHandle
friend class QPDF_Dictionary; friend class QPDF_Dictionary;
friend class QPDF_Stream; friend class QPDF_Stream;
friend class SparseOHArray; friend class SparseOHArray;
private: private:
static void releaseResolved(QPDFObjectHandle& o) static void
releaseResolved(QPDFObjectHandle& o)
{ {
o.releaseResolved(); o.releaseResolved();
} }
@ -1433,14 +1456,13 @@ class QPDFObjectHandle
// Indicate if this is an image. If exclude_imagemask is true, // Indicate if this is an image. If exclude_imagemask is true,
// don't count image masks as images. // don't count image masks as images.
QPDF_DLL QPDF_DLL
bool isImage(bool exclude_imagemask=true); bool isImage(bool exclude_imagemask = true);
private: private:
QPDFObjectHandle(QPDF*, int objid, int generation); QPDFObjectHandle(QPDF*, int objid, int generation);
QPDFObjectHandle(QPDFObject*); QPDFObjectHandle(QPDFObject*);
enum parser_state_e enum parser_state_e {
{
st_top, st_top,
st_start, st_start,
st_stop, st_stop,
@ -1452,31 +1474,41 @@ class QPDFObjectHandle
// Private object factory methods // Private object factory methods
static QPDFObjectHandle newIndirect(QPDF*, int objid, int generation); static QPDFObjectHandle newIndirect(QPDF*, int objid, int generation);
static QPDFObjectHandle newStream( static QPDFObjectHandle newStream(
QPDF* qpdf, int objid, int generation, QPDF* qpdf,
QPDFObjectHandle stream_dict, qpdf_offset_t offset, size_t length); int objid,
int generation,
QPDFObjectHandle stream_dict,
qpdf_offset_t offset,
size_t length);
void typeWarning(char const* expected_type, void typeWarning(char const* expected_type, std::string const& warning);
std::string const& warning);
void objectWarning(std::string const& warning); void objectWarning(std::string const& warning);
void assertType(char const* type_name, bool istype); void assertType(char const* type_name, bool istype);
void dereference(); void dereference();
void copyObject(std::set<QPDFObjGen>& visited, bool cross_indirect, void copyObject(
bool first_level_only, bool stop_at_streams); std::set<QPDFObjGen>& visited,
bool cross_indirect,
bool first_level_only,
bool stop_at_streams);
void shallowCopyInternal(QPDFObjectHandle& oh, bool first_level_only); void shallowCopyInternal(QPDFObjectHandle& oh, bool first_level_only);
void releaseResolved(); void releaseResolved();
static void setObjectDescriptionFromInput( static void setObjectDescriptionFromInput(
QPDFObjectHandle, QPDF*, std::string const&, QPDFObjectHandle,
PointerHolder<InputSource>, qpdf_offset_t); QPDF*,
std::string const&,
PointerHolder<InputSource>,
qpdf_offset_t);
static QPDFObjectHandle parseInternal( static QPDFObjectHandle parseInternal(
PointerHolder<InputSource> input, PointerHolder<InputSource> input,
std::string const& object_description, std::string const& object_description,
QPDFTokenizer& tokenizer, bool& empty, QPDFTokenizer& tokenizer,
StringDecrypter* decrypter, QPDF* context, bool& empty,
StringDecrypter* decrypter,
QPDF* context,
bool content_stream); bool content_stream);
void setParsedOffset(qpdf_offset_t offset); void setParsedOffset(qpdf_offset_t offset);
void parseContentStream_internal( void parseContentStream_internal(
std::string const& description, std::string const& description, ParserCallbacks* callbacks);
ParserCallbacks* callbacks);
static void parseContentStream_data( static void parseContentStream_data(
PointerHolder<Buffer>, PointerHolder<Buffer>,
std::string const& description, std::string const& description,
@ -1493,7 +1525,7 @@ class QPDFObjectHandle
// a substantial performance penalty since QPDFObjectHandle // a substantial performance penalty since QPDFObjectHandle
// objects are copied around so frequently. // objects are copied around so frequently.
QPDF* qpdf; QPDF* qpdf;
int objid; // 0 for direct object int objid; // 0 for direct object
int generation; int generation;
PointerHolder<QPDFObject> obj; PointerHolder<QPDFObject> obj;
bool reserved; bool reserved;
@ -1507,7 +1539,7 @@ class QPDFObjectHandle
// If this is causing problems in your code, define // If this is causing problems in your code, define
// QPDF_NO_QPDF_STRING to prevent the declaration from being here. // QPDF_NO_QPDF_STRING to prevent the declaration from being here.
QPDF_DLL QPDF_DLL
QPDFObjectHandle operator ""_qpdf(char const* v, size_t len); QPDFObjectHandle operator""_qpdf(char const* v, size_t len);
#endif // QPDF_NO_QPDF_STRING #endif // QPDF_NO_QPDF_STRING
class QPDFObjectHandle::QPDFDictItems class QPDFObjectHandle::QPDFDictItems
@ -1531,6 +1563,7 @@ class QPDFObjectHandle::QPDFDictItems
class iterator class iterator
{ {
friend class QPDFDictItems; friend class QPDFDictItems;
public: public:
typedef std::pair<std::string, QPDFObjectHandle> T; typedef std::pair<std::string, QPDFObjectHandle> T;
using iterator_category = std::bidirectional_iterator_tag; using iterator_category = std::bidirectional_iterator_tag;
@ -1544,7 +1577,8 @@ class QPDFObjectHandle::QPDFDictItems
QPDF_DLL QPDF_DLL
iterator& operator++(); iterator& operator++();
QPDF_DLL QPDF_DLL
iterator operator++(int) iterator
operator++(int)
{ {
iterator t = *this; iterator t = *this;
++(*this); ++(*this);
@ -1553,7 +1587,8 @@ class QPDFObjectHandle::QPDFDictItems
QPDF_DLL QPDF_DLL
iterator& operator--(); iterator& operator--();
QPDF_DLL QPDF_DLL
iterator operator--(int) iterator
operator--(int)
{ {
iterator t = *this; iterator t = *this;
--(*this); --(*this);
@ -1566,9 +1601,10 @@ class QPDFObjectHandle::QPDFDictItems
QPDF_DLL QPDF_DLL
bool operator==(iterator const& other) const; bool operator==(iterator const& other) const;
QPDF_DLL QPDF_DLL
bool operator!=(iterator const& other) const bool
operator!=(iterator const& other) const
{ {
return ! operator==(other); return !operator==(other);
} }
private: private:
@ -1626,6 +1662,7 @@ class QPDFObjectHandle::QPDFArrayItems
class iterator class iterator
{ {
friend class QPDFArrayItems; friend class QPDFArrayItems;
public: public:
typedef QPDFObjectHandle T; typedef QPDFObjectHandle T;
using iterator_category = std::bidirectional_iterator_tag; using iterator_category = std::bidirectional_iterator_tag;
@ -1639,7 +1676,8 @@ class QPDFObjectHandle::QPDFArrayItems
QPDF_DLL QPDF_DLL
iterator& operator++(); iterator& operator++();
QPDF_DLL QPDF_DLL
iterator operator++(int) iterator
operator++(int)
{ {
iterator t = *this; iterator t = *this;
++(*this); ++(*this);
@ -1648,7 +1686,8 @@ class QPDFObjectHandle::QPDFArrayItems
QPDF_DLL QPDF_DLL
iterator& operator--(); iterator& operator--();
QPDF_DLL QPDF_DLL
iterator operator--(int) iterator
operator--(int)
{ {
iterator t = *this; iterator t = *this;
--(*this); --(*this);
@ -1661,9 +1700,10 @@ class QPDFObjectHandle::QPDFArrayItems
QPDF_DLL QPDF_DLL
bool operator==(iterator const& other) const; bool operator==(iterator const& other) const;
QPDF_DLL QPDF_DLL
bool operator!=(iterator const& other) const bool
operator!=(iterator const& other) const
{ {
return ! operator==(other); return !operator==(other);
} }
private: private:
@ -1700,5 +1740,4 @@ class QPDFObjectHandle::QPDFArrayItems
QPDFObjectHandle oh; QPDFObjectHandle oh;
}; };
#endif // QPDFOBJECTHANDLE_HH #endif // QPDFOBJECTHANDLE_HH

View File

@ -50,12 +50,14 @@ class QPDFObjectHelper
{ {
} }
QPDF_DLL QPDF_DLL
QPDFObjectHandle getObjectHandle() QPDFObjectHandle
getObjectHandle()
{ {
return this->oh; return this->oh;
} }
QPDF_DLL QPDF_DLL
QPDFObjectHandle const getObjectHandle() const QPDFObjectHandle const
getObjectHandle() const
{ {
return this->oh; return this->oh;
} }

View File

@ -23,8 +23,8 @@
#define QPDFOUTLINEDOCUMENTHELPER_HH #define QPDFOUTLINEDOCUMENTHELPER_HH
#include <qpdf/QPDFDocumentHelper.hh> #include <qpdf/QPDFDocumentHelper.hh>
#include <qpdf/QPDFOutlineObjectHelper.hh>
#include <qpdf/QPDFNameTreeObjectHelper.hh> #include <qpdf/QPDFNameTreeObjectHelper.hh>
#include <qpdf/QPDFOutlineObjectHelper.hh>
#include <qpdf/QPDF.hh> #include <qpdf/QPDF.hh>
#include <map> #include <map>
@ -58,8 +58,7 @@ class QPDFOutlineDocumentHelper: public QPDFDocumentHelper
// the name tree pointed to by the /Dests key of the names // the name tree pointed to by the /Dests key of the names
// dictionary. // dictionary.
QPDF_DLL QPDF_DLL
QPDFObjectHandle QPDFObjectHandle resolveNamedDest(QPDFObjectHandle name);
resolveNamedDest(QPDFObjectHandle name);
// Return a list outlines that are known to target the specified // Return a list outlines that are known to target the specified
// page // page
@ -99,7 +98,7 @@ class QPDFOutlineDocumentHelper: public QPDFDocumentHelper
std::set<QPDFObjGen> seen; std::set<QPDFObjGen> seen;
QPDFObjectHandle dest_dict; QPDFObjectHandle dest_dict;
PointerHolder<QPDFNameTreeObjectHelper> names_dest; PointerHolder<QPDFNameTreeObjectHelper> names_dest;
std::map<QPDFObjGen, std::vector<QPDFOutlineObjectHelper> > by_page; std::map<QPDFObjGen, std::vector<QPDFOutlineObjectHelper>> by_page;
}; };
PointerHolder<Members> m; PointerHolder<Members> m;

View File

@ -22,8 +22,8 @@
#ifndef QPDFOUTLINEOBJECTHELPER_HH #ifndef QPDFOUTLINEOBJECTHELPER_HH
#define QPDFOUTLINEOBJECTHELPER_HH #define QPDFOUTLINEOBJECTHELPER_HH
#include <qpdf/QPDFObjectHelper.hh>
#include <qpdf/QPDFObjGen.hh> #include <qpdf/QPDFObjGen.hh>
#include <qpdf/QPDFObjectHelper.hh>
#include <vector> #include <vector>
class QPDFOutlineDocumentHelper; class QPDFOutlineDocumentHelper;

View File

@ -22,9 +22,9 @@
#ifndef QPDFPAGEDOCUMENTHELPER_HH #ifndef QPDFPAGEDOCUMENTHELPER_HH
#define QPDFPAGEDOCUMENTHELPER_HH #define QPDFPAGEDOCUMENTHELPER_HH
#include <qpdf/Constants.h>
#include <qpdf/QPDFDocumentHelper.hh> #include <qpdf/QPDFDocumentHelper.hh>
#include <qpdf/QPDFPageObjectHelper.hh> #include <qpdf/QPDFPageObjectHelper.hh>
#include <qpdf/Constants.h>
#include <qpdf/DLL.h> #include <qpdf/DLL.h>
@ -106,8 +106,10 @@ class QPDFPageDocumentHelper: public QPDFDocumentHelper
// Add new page before or after refpage. See comments for addPage // Add new page before or after refpage. See comments for addPage
// for details about what newpage should be. // for details about what newpage should be.
QPDF_DLL QPDF_DLL
void addPageAt(QPDFPageObjectHelper newpage, bool before, void addPageAt(
QPDFPageObjectHelper refpage); QPDFPageObjectHelper newpage,
bool before,
QPDFPageObjectHelper refpage);
// Remove page from the pdf. // Remove page from the pdf.
QPDF_DLL QPDF_DLL
@ -126,8 +128,7 @@ class QPDFPageDocumentHelper: public QPDFDocumentHelper
// those flags. // those flags.
QPDF_DLL QPDF_DLL
void flattenAnnotations( void flattenAnnotations(
int required_flags = 0, int required_flags = 0, int forbidden_flags = an_invisible | an_hidden);
int forbidden_flags = an_invisible | an_hidden);
private: private:
void flattenAnnotationsForPage( void flattenAnnotationsForPage(

View File

@ -77,10 +77,11 @@ class QPDFPageLabelDocumentHelper: public QPDFDocumentHelper
// behavior facilitates using this function to incrementally build // behavior facilitates using this function to incrementally build
// up a page labels tree when merging files. // up a page labels tree when merging files.
QPDF_DLL QPDF_DLL
void void getLabelsForPageRange(
getLabelsForPageRange(long long start_idx, long long end_idx, long long start_idx,
long long new_start_idx, long long end_idx,
std::vector<QPDFObjectHandle>& new_labels); long long new_start_idx,
std::vector<QPDFObjectHandle>& new_labels);
private: private:
class Members class Members

View File

@ -22,9 +22,9 @@
#ifndef QPDFPAGEOBJECTHELPER_HH #ifndef QPDFPAGEOBJECTHELPER_HH
#define QPDFPAGEOBJECTHELPER_HH #define QPDFPAGEOBJECTHELPER_HH
#include <qpdf/QPDFObjectHelper.hh>
#include <qpdf/QPDFAnnotationObjectHelper.hh> #include <qpdf/QPDFAnnotationObjectHelper.hh>
#include <qpdf/QPDFMatrix.hh> #include <qpdf/QPDFMatrix.hh>
#include <qpdf/QPDFObjectHelper.hh>
#include <qpdf/DLL.h> #include <qpdf/DLL.h>
@ -57,23 +57,19 @@ class QPDFPageObjectHelper: public QPDFObjectHelper
// going to modify the returned object and want the modifications // going to modify the returned object and want the modifications
// to apply to the current page/form XObject only. // to apply to the current page/form XObject only.
QPDF_DLL QPDF_DLL
QPDFObjectHandle QPDFObjectHandle getAttribute(std::string const& name, bool copy_if_shared);
getAttribute(std::string const& name, bool copy_if_shared);
// Return the TrimBox. If not defined, fall back to CropBox // Return the TrimBox. If not defined, fall back to CropBox
QPDF_DLL QPDF_DLL
QPDFObjectHandle QPDFObjectHandle getTrimBox(bool copy_if_shared = false);
getTrimBox(bool copy_if_shared = false);
// Return the CropBox. If not defined, fall back to MediaBox // Return the CropBox. If not defined, fall back to MediaBox
QPDF_DLL QPDF_DLL
QPDFObjectHandle QPDFObjectHandle getCropBox(bool copy_if_shared = false);
getCropBox(bool copy_if_shared = false);
// Return the MediaBox // Return the MediaBox
QPDF_DLL QPDF_DLL
QPDFObjectHandle QPDFObjectHandle getMediaBox(bool copy_if_shared = false);
getMediaBox(bool copy_if_shared = false);
// Iterate through XObjects, possibly recursing into form // Iterate through XObjects, possibly recursing into form
// XObjects. This works with pages or form XObjects. Call action // XObjects. This works with pages or form XObjects. Call action
@ -86,24 +82,27 @@ class QPDFPageObjectHelper: public QPDFObjectHelper
QPDF_DLL QPDF_DLL
void forEachXObject( void forEachXObject(
bool recursive, bool recursive,
std::function<void(QPDFObjectHandle& obj, std::function<void(
QPDFObjectHandle& xobj_dict, QPDFObjectHandle& obj,
std::string const& key)> action, QPDFObjectHandle& xobj_dict,
std::function<bool(QPDFObjectHandle)> selector=nullptr); std::string const& key)> action,
std::function<bool(QPDFObjectHandle)> selector = nullptr);
// Only call action for images // Only call action for images
QPDF_DLL QPDF_DLL
void forEachImage( void forEachImage(
bool recursive, bool recursive,
std::function<void(QPDFObjectHandle& obj, std::function<void(
QPDFObjectHandle& xobj_dict, QPDFObjectHandle& obj,
std::string const& key)> action); QPDFObjectHandle& xobj_dict,
std::string const& key)> action);
// Only call action for form XObjects // Only call action for form XObjects
QPDF_DLL QPDF_DLL
void forEachFormXObject( void forEachFormXObject(
bool recursive, bool recursive,
std::function<void(QPDFObjectHandle& obj, std::function<void(
QPDFObjectHandle& xobj_dict, QPDFObjectHandle& obj,
std::string const& key)> action); QPDFObjectHandle& xobj_dict,
std::string const& key)> action);
// Returns an empty map if there are no images or no resources. // Returns an empty map if there are no images or no resources.
// Prior to qpdf 8.4.0, this function did not support inherited // Prior to qpdf 8.4.0, this function did not support inherited
@ -142,8 +141,8 @@ class QPDFPageObjectHelper: public QPDFObjectHelper
// only_subtype is non-empty, only include annotations of the // only_subtype is non-empty, only include annotations of the
// given subtype. // given subtype.
QPDF_DLL QPDF_DLL
std::vector<QPDFAnnotationObjectHelper> getAnnotations( std::vector<QPDFAnnotationObjectHelper>
std::string const& only_subtype = ""); getAnnotations(std::string const& only_subtype = "");
// Returns a vector of stream objects representing the content // Returns a vector of stream objects representing the content
// streams for the given page. This routine allows the caller to // streams for the given page. This routine allows the caller to
@ -203,13 +202,13 @@ class QPDFPageObjectHelper: public QPDFObjectHelper
// contents, as happens with addContentTokenFilter. See // contents, as happens with addContentTokenFilter. See
// examples/pdf-count-strings.cc for an example. // examples/pdf-count-strings.cc for an example.
QPDF_DLL QPDF_DLL
void filterContents(QPDFObjectHandle::TokenFilter* filter, void
Pipeline* next = 0); filterContents(QPDFObjectHandle::TokenFilter* filter, Pipeline* next = 0);
// Old name -- calls filterContents() // Old name -- calls filterContents()
QPDF_DLL QPDF_DLL
void filterPageContents(QPDFObjectHandle::TokenFilter* filter, void filterPageContents(
Pipeline* next = 0); QPDFObjectHandle::TokenFilter* filter, Pipeline* next = 0);
// Pipe a page's contents through the given pipeline. This method // Pipe a page's contents through the given pipeline. This method
// works whether the contents are a single stream or an array of // works whether the contents are a single stream or an array of
@ -303,7 +302,8 @@ class QPDFPageObjectHelper: public QPDFObjectHelper
// behavior. // behavior.
QPDF_DLL QPDF_DLL
std::string placeFormXObject( std::string placeFormXObject(
QPDFObjectHandle fo, std::string const& name, QPDFObjectHandle fo,
std::string const& name,
QPDFObjectHandle::Rectangle rect, QPDFObjectHandle::Rectangle rect,
bool invert_transformations = true, bool invert_transformations = true,
bool allow_shrink = true, bool allow_shrink = true,
@ -313,7 +313,8 @@ class QPDFPageObjectHelper: public QPDFObjectHelper
// matrix that was used. // matrix that was used.
QPDF_DLL QPDF_DLL
std::string placeFormXObject( std::string placeFormXObject(
QPDFObjectHandle fo, std::string const& name, QPDFObjectHandle fo,
std::string const& name,
QPDFObjectHandle::Rectangle rect, QPDFObjectHandle::Rectangle rect,
QPDFMatrix& cm, QPDFMatrix& cm,
bool invert_transformations = true, bool invert_transformations = true,
@ -326,9 +327,11 @@ class QPDFPageObjectHelper: public QPDFObjectHelper
// placeFormXObject. // placeFormXObject.
QPDF_DLL QPDF_DLL
QPDFMatrix getMatrixForFormXObjectPlacement( QPDFMatrix getMatrixForFormXObjectPlacement(
QPDFObjectHandle fo, QPDFObjectHandle::Rectangle rect, QPDFObjectHandle fo,
QPDFObjectHandle::Rectangle rect,
bool invert_transformations = true, bool invert_transformations = true,
bool allow_shrink = true, bool allow_expand = false); bool allow_shrink = true,
bool allow_expand = false);
// If a page is rotated using /Rotate in the page's dictionary, // If a page is rotated using /Rotate in the page's dictionary,
// instead rotate the page by the same amount by altering the // instead rotate the page by the same amount by altering the
@ -372,13 +375,13 @@ class QPDFPageObjectHelper: public QPDFObjectHelper
// these outside and pass them in. // these outside and pass them in.
QPDF_DLL QPDF_DLL
void copyAnnotations( void copyAnnotations(
QPDFPageObjectHelper from_page, QPDFMatrix const& cm = QPDFMatrix(), QPDFPageObjectHelper from_page,
QPDFMatrix const& cm = QPDFMatrix(),
QPDFAcroFormDocumentHelper* afdh = nullptr, QPDFAcroFormDocumentHelper* afdh = nullptr,
QPDFAcroFormDocumentHelper* from_afdh = nullptr); QPDFAcroFormDocumentHelper* from_afdh = nullptr);
private: private:
static bool static bool removeUnreferencedResourcesHelper(
removeUnreferencedResourcesHelper(
QPDFPageObjectHelper ph, std::set<std::string>& unresolved); QPDFPageObjectHelper ph, std::set<std::string>& unresolved);
class Members class Members

View File

@ -23,8 +23,8 @@
#define QPDFSTREAMFILTER_HH #define QPDFSTREAMFILTER_HH
#include <qpdf/DLL.h> #include <qpdf/DLL.h>
#include <qpdf/QPDFObjectHandle.hh>
#include <qpdf/Pipeline.hh> #include <qpdf/Pipeline.hh>
#include <qpdf/QPDFObjectHandle.hh>
class QPDF_DLL_CLASS QPDFStreamFilter class QPDF_DLL_CLASS QPDFStreamFilter
{ {

View File

@ -22,19 +22,18 @@
#ifndef QPDFSYSTEMERROR_HH #ifndef QPDFSYSTEMERROR_HH
#define QPDFSYSTEMERROR_HH #define QPDFSYSTEMERROR_HH
#include <qpdf/Constants.h>
#include <qpdf/DLL.h> #include <qpdf/DLL.h>
#include <qpdf/Types.h> #include <qpdf/Types.h>
#include <qpdf/Constants.h>
#include <string>
#include <stdexcept> #include <stdexcept>
#include <string>
class QPDF_DLL_CLASS QPDFSystemError: public std::runtime_error class QPDF_DLL_CLASS QPDFSystemError: public std::runtime_error
{ {
public: public:
QPDF_DLL QPDF_DLL
QPDFSystemError(std::string const& description, QPDFSystemError(std::string const& description, int system_errno);
int system_errno);
QPDF_DLL QPDF_DLL
virtual ~QPDFSystemError() noexcept; virtual ~QPDFSystemError() noexcept;
@ -48,8 +47,8 @@ class QPDF_DLL_CLASS QPDFSystemError: public std::runtime_error
int getErrno() const; int getErrno() const;
private: private:
static std::string createWhat(std::string const& description, static std::string
int system_errno); createWhat(std::string const& description, int system_errno);
// This class does not use the Members pattern to avoid needless // This class does not use the Members pattern to avoid needless
// memory allocations during exception handling. // memory allocations during exception handling.

View File

@ -27,9 +27,9 @@
#include <qpdf/InputSource.hh> #include <qpdf/InputSource.hh>
#include <qpdf/PointerHolder.hh> #include <qpdf/PointerHolder.hh>
#include <string>
#include <stdio.h>
#include <memory> #include <memory>
#include <stdio.h>
#include <string>
class QPDFTokenizer class QPDFTokenizer
{ {
@ -38,8 +38,7 @@ class QPDFTokenizer
// the tokenizer. tt_eof was introduced in QPDF version 4.1. // the tokenizer. tt_eof was introduced in QPDF version 4.1.
// tt_space, tt_comment, and tt_inline_image were added in QPDF // tt_space, tt_comment, and tt_inline_image were added in QPDF
// version 8. // version 8.
enum token_type_e enum token_type_e {
{
tt_bad, tt_bad,
tt_array_close, tt_array_close,
tt_array_open, tt_array_open,
@ -63,39 +62,50 @@ class QPDFTokenizer
class Token class Token
{ {
public: public:
Token() : type(tt_bad) {} Token() :
type(tt_bad)
{
}
QPDF_DLL QPDF_DLL
Token(token_type_e type, std::string const& value); Token(token_type_e type, std::string const& value);
Token(token_type_e type, std::string const& value, Token(
std::string raw_value, std::string error_message) : token_type_e type,
std::string const& value,
std::string raw_value,
std::string error_message) :
type(type), type(type),
value(value), value(value),
raw_value(raw_value), raw_value(raw_value),
error_message(error_message) error_message(error_message)
{ {
} }
token_type_e getType() const token_type_e
getType() const
{ {
return this->type; return this->type;
} }
std::string const& getValue() const std::string const&
getValue() const
{ {
return this->value; return this->value;
} }
std::string const& getRawValue() const std::string const&
getRawValue() const
{ {
return this->raw_value; return this->raw_value;
} }
std::string const& getErrorMessage() const std::string const&
getErrorMessage() const
{ {
return this->error_message; return this->error_message;
} }
bool operator==(Token const& rhs) const bool
operator==(Token const& rhs) const
{ {
// Ignore fields other than type and value // Ignore fields other than type and value
return ((this->type != tt_bad) && return (
(this->type == rhs.type) && (this->type != tt_bad) && (this->type == rhs.type) &&
(this->value == rhs.value)); (this->value == rhs.value));
} }
private: private:
@ -162,10 +172,11 @@ class QPDFTokenizer
// offset" as returned by input->getLastOffset() points to the // offset" as returned by input->getLastOffset() points to the
// beginning of the token. // beginning of the token.
QPDF_DLL QPDF_DLL
Token readToken(PointerHolder<InputSource> input, Token readToken(
std::string const& context, PointerHolder<InputSource> input,
bool allow_bad = false, std::string const& context,
size_t max_len = 0); bool allow_bad = false,
size_t max_len = 0);
// Calling this method puts the tokenizer in a state for reading // Calling this method puts the tokenizer in a state for reading
// inline images. You should call this method after reading the // inline images. You should call this method after reading the
@ -188,8 +199,16 @@ class QPDFTokenizer
void findEI(PointerHolder<InputSource> input); void findEI(PointerHolder<InputSource> input);
enum state_e { enum state_e {
st_top, st_in_space, st_in_comment, st_in_string, st_lt, st_gt, st_top,
st_literal, st_in_hexstring, st_inline_image, st_token_ready st_in_space,
st_in_comment,
st_in_string,
st_lt,
st_gt,
st_literal,
st_in_hexstring,
st_inline_image,
st_token_ready
}; };
class Members class Members

View File

@ -24,8 +24,8 @@
#include <qpdf/DLL.h> #include <qpdf/DLL.h>
#include <string>
#include <stdexcept> #include <stdexcept>
#include <string>
class QPDF_DLL_CLASS QPDFUsage: public std::runtime_error class QPDF_DLL_CLASS QPDFUsage: public std::runtime_error
{ {

View File

@ -29,24 +29,24 @@
#include <qpdf/DLL.h> #include <qpdf/DLL.h>
#include <qpdf/Types.h> #include <qpdf/Types.h>
#include <stdio.h>
#include <string>
#include <list> #include <list>
#include <vector>
#include <set>
#include <map> #include <map>
#include <memory> #include <memory>
#include <set>
#include <stdio.h>
#include <string>
#include <vector>
#include <qpdf/Constants.h> #include <qpdf/Constants.h>
#include <qpdf/QPDFObjectHandle.hh>
#include <qpdf/QPDFObjGen.hh>
#include <qpdf/QPDFXRefEntry.hh>
#include <qpdf/Pl_Buffer.hh>
#include <qpdf/PointerHolder.hh>
#include <qpdf/Pipeline.hh>
#include <qpdf/Buffer.hh> #include <qpdf/Buffer.hh>
#include <qpdf/PDFVersion.hh> #include <qpdf/PDFVersion.hh>
#include <qpdf/Pipeline.hh>
#include <qpdf/Pl_Buffer.hh>
#include <qpdf/PointerHolder.hh>
#include <qpdf/QPDFObjGen.hh>
#include <qpdf/QPDFObjectHandle.hh>
#include <qpdf/QPDFXRefEntry.hh>
class QPDF; class QPDF;
class Pl_Count; class Pl_Count;
@ -372,72 +372,104 @@ class QPDFWriter
// it unless you have to. // it unless you have to.
QPDF_DLL QPDF_DLL
void setR2EncryptionParameters( void setR2EncryptionParameters(
char const* user_password, char const* owner_password, char const* user_password,
bool allow_print, bool allow_modify, char const* owner_password,
bool allow_extract, bool allow_annotate); bool allow_print,
bool allow_modify,
bool allow_extract,
bool allow_annotate);
// R3 uses RC4, which is a weak cryptographic algorithm. Don't use // R3 uses RC4, which is a weak cryptographic algorithm. Don't use
// it unless you have to. // it unless you have to.
QPDF_DLL QPDF_DLL
void setR3EncryptionParameters( void setR3EncryptionParameters(
char const* user_password, char const* owner_password, char const* user_password,
bool allow_accessibility, bool allow_extract, char const* owner_password,
bool allow_assemble, bool allow_annotate_and_form, bool allow_accessibility,
bool allow_form_filling, bool allow_modify_other, bool allow_extract,
bool allow_assemble,
bool allow_annotate_and_form,
bool allow_form_filling,
bool allow_modify_other,
qpdf_r3_print_e print); qpdf_r3_print_e print);
// R4 uses RC4, which is a weak cryptographic algorithm, when // R4 uses RC4, which is a weak cryptographic algorithm, when
// use_aes=false. Don't use it unless you have to. // use_aes=false. Don't use it unless you have to.
QPDF_DLL QPDF_DLL
void setR4EncryptionParameters( void setR4EncryptionParameters(
char const* user_password, char const* owner_password, char const* user_password,
bool allow_accessibility, bool allow_extract, char const* owner_password,
bool allow_assemble, bool allow_annotate_and_form, bool allow_accessibility,
bool allow_form_filling, bool allow_modify_other, bool allow_extract,
qpdf_r3_print_e print, bool encrypt_metadata, bool use_aes); bool allow_assemble,
bool allow_annotate_and_form,
bool allow_form_filling,
bool allow_modify_other,
qpdf_r3_print_e print,
bool encrypt_metadata,
bool use_aes);
// R5 is deprecated. Do not use it for production use. Writing // R5 is deprecated. Do not use it for production use. Writing
// R5 is supported by qpdf primarily to generate test files for // R5 is supported by qpdf primarily to generate test files for
// applications that may need to test R5 support. // applications that may need to test R5 support.
QPDF_DLL QPDF_DLL
void setR5EncryptionParameters( void setR5EncryptionParameters(
char const* user_password, char const* owner_password, char const* user_password,
bool allow_accessibility, bool allow_extract, char const* owner_password,
bool allow_assemble, bool allow_annotate_and_form, bool allow_accessibility,
bool allow_form_filling, bool allow_modify_other, bool allow_extract,
qpdf_r3_print_e print, bool encrypt_metadata); bool allow_assemble,
bool allow_annotate_and_form,
bool allow_form_filling,
bool allow_modify_other,
qpdf_r3_print_e print,
bool encrypt_metadata);
QPDF_DLL QPDF_DLL
void setR6EncryptionParameters( void setR6EncryptionParameters(
char const* user_password, char const* owner_password, char const* user_password,
bool allow_accessibility, bool allow_extract, char const* owner_password,
bool allow_assemble, bool allow_annotate_and_form, bool allow_accessibility,
bool allow_form_filling, bool allow_modify_other, bool allow_extract,
qpdf_r3_print_e print, bool encrypt_metadata_aes); bool allow_assemble,
bool allow_annotate_and_form,
bool allow_form_filling,
bool allow_modify_other,
qpdf_r3_print_e print,
bool encrypt_metadata_aes);
// Pre qpdf 8.4.0 API // Pre qpdf 8.4.0 API
[[deprecated("see newer API above")]] [[deprecated("see newer API above")]] QPDF_DLL void
QPDF_DLL setR3EncryptionParameters(
void setR3EncryptionParameters( char const* user_password,
char const* user_password, char const* owner_password, char const* owner_password,
bool allow_accessibility, bool allow_extract, bool allow_accessibility,
qpdf_r3_print_e print, qpdf_r3_modify_e modify); bool allow_extract,
[[deprecated("see newer API above")]] qpdf_r3_print_e print,
QPDF_DLL qpdf_r3_modify_e modify);
void setR4EncryptionParameters( [[deprecated("see newer API above")]] QPDF_DLL void
char const* user_password, char const* owner_password, setR4EncryptionParameters(
bool allow_accessibility, bool allow_extract, char const* user_password,
qpdf_r3_print_e print, qpdf_r3_modify_e modify, char const* owner_password,
bool encrypt_metadata, bool use_aes); bool allow_accessibility,
[[deprecated("see newer API above")]] bool allow_extract,
QPDF_DLL qpdf_r3_print_e print,
void setR5EncryptionParameters( qpdf_r3_modify_e modify,
char const* user_password, char const* owner_password, bool encrypt_metadata,
bool allow_accessibility, bool allow_extract, bool use_aes);
qpdf_r3_print_e print, qpdf_r3_modify_e modify, [[deprecated("see newer API above")]] QPDF_DLL void
setR5EncryptionParameters(
char const* user_password,
char const* owner_password,
bool allow_accessibility,
bool allow_extract,
qpdf_r3_print_e print,
qpdf_r3_modify_e modify,
bool encrypt_metadata); bool encrypt_metadata);
[[deprecated("see newer API above")]] [[deprecated("see newer API above")]] QPDF_DLL void
QPDF_DLL setR6EncryptionParameters(
void setR6EncryptionParameters( char const* user_password,
char const* user_password, char const* owner_password, char const* owner_password,
bool allow_accessibility, bool allow_extract, bool allow_accessibility,
qpdf_r3_print_e print, qpdf_r3_modify_e modify, bool allow_extract,
qpdf_r3_print_e print,
qpdf_r3_modify_e modify,
bool encrypt_metadata_aes); bool encrypt_metadata_aes);
// Create linearized output. Disables qdf mode, content // Create linearized output. Disables qdf mode, content
@ -496,11 +528,11 @@ class QPDFWriter
private: private:
// flags used by unparseObject // flags used by unparseObject
static int const f_stream = 1 << 0; static int const f_stream = 1 << 0;
static int const f_filtered = 1 << 1; static int const f_filtered = 1 << 1;
static int const f_in_ostream = 1 << 2; static int const f_in_ostream = 1 << 2;
static int const f_hex_string = 1 << 3; static int const f_hex_string = 1 << 3;
static int const f_no_encryption = 1 << 4; static int const f_no_encryption = 1 << 4;
enum trailer_e { t_normal, t_lin_first, t_lin_second }; enum trailer_e { t_normal, t_lin_first, t_lin_second };
@ -516,9 +548,9 @@ class QPDFWriter
class PipelinePopper class PipelinePopper
{ {
friend class QPDFWriter; friend class QPDFWriter;
public: public:
PipelinePopper(QPDFWriter* qw, PipelinePopper(QPDFWriter* qw, PointerHolder<Buffer>* bp = 0) :
PointerHolder<Buffer>* bp = 0) :
qw(qw), qw(qw),
bp(bp) bp(bp)
{ {
@ -545,15 +577,24 @@ class QPDFWriter
std::vector<qpdf_offset_t>& offsets, int first_obj); std::vector<qpdf_offset_t>& offsets, int first_obj);
void writeObjectStream(QPDFObjectHandle object); void writeObjectStream(QPDFObjectHandle object);
void writeObject(QPDFObjectHandle object, int object_stream_index = -1); void writeObject(QPDFObjectHandle object, int object_stream_index = -1);
void writeTrailer(trailer_e which, int size, void writeTrailer(
bool xref_stream, qpdf_offset_t prev, trailer_e which,
int linearization_pass); int size,
bool willFilterStream(QPDFObjectHandle stream, bool xref_stream,
bool& compress_stream, bool& is_metadata, qpdf_offset_t prev,
PointerHolder<Buffer>* stream_data); int linearization_pass);
void unparseObject(QPDFObjectHandle object, int level, int flags, bool willFilterStream(
// for stream dictionaries QPDFObjectHandle stream,
size_t stream_length = 0, bool compress = false); bool& compress_stream,
bool& is_metadata,
PointerHolder<Buffer>* stream_data);
void unparseObject(
QPDFObjectHandle object,
int level,
int flags,
// for stream dictionaries
size_t stream_length = 0,
bool compress = false);
void unparseChild(QPDFObjectHandle child, int level, int flags); void unparseChild(QPDFObjectHandle child, int level, int flags);
void initializeSpecialStreams(); void initializeSpecialStreams();
void preserveObjectStreams(); void preserveObjectStreams();
@ -562,23 +603,39 @@ class QPDFWriter
void generateID(); void generateID();
void interpretR3EncryptionParameters( void interpretR3EncryptionParameters(
std::set<int>& bits_to_clear, std::set<int>& bits_to_clear,
char const* user_password, char const* owner_password, char const* user_password,
bool allow_accessibility, bool allow_extract, char const* owner_password,
bool allow_assemble, bool allow_annotate_and_form, bool allow_accessibility,
bool allow_form_filling, bool allow_modify_other, bool allow_extract,
qpdf_r3_print_e print, qpdf_r3_modify_e modify); bool allow_assemble,
void disableIncompatibleEncryption(int major, int minor, bool allow_annotate_and_form,
int extension_level); bool allow_form_filling,
bool allow_modify_other,
qpdf_r3_print_e print,
qpdf_r3_modify_e modify);
void
disableIncompatibleEncryption(int major, int minor, int extension_level);
void parseVersion(std::string const& version, int& major, int& minor) const; void parseVersion(std::string const& version, int& major, int& minor) const;
int compareVersions(int major1, int minor1, int major2, int minor2) const; int compareVersions(int major1, int minor1, int major2, int minor2) const;
void setEncryptionParameters( void setEncryptionParameters(
char const* user_password, char const* owner_password, char const* user_password,
int V, int R, int key_len, std::set<int>& bits_to_clear); char const* owner_password,
int V,
int R,
int key_len,
std::set<int>& bits_to_clear);
void setEncryptionParametersInternal( void setEncryptionParametersInternal(
int V, int R, int key_len, int P, int V,
std::string const& O, std::string const& U, int R,
std::string const& OE, std::string const& UE, std::string const& Perms, int key_len,
std::string const& id1, std::string const& user_password, int P,
std::string const& O,
std::string const& U,
std::string const& OE,
std::string const& UE,
std::string const& Perms,
std::string const& id1,
std::string const& user_password,
std::string const& encryption_key); std::string const& encryption_key);
void setDataKey(int objid); void setDataKey(int objid);
int openObject(int objid = 0); int openObject(int objid = 0);
@ -595,10 +652,13 @@ class QPDFWriter
void doWriteSetup(); void doWriteSetup();
void writeHeader(); void writeHeader();
void writeHintStream(int hint_id); void writeHintStream(int hint_id);
qpdf_offset_t
writeXRefTable(trailer_e which, int first, int last, int size);
qpdf_offset_t writeXRefTable( qpdf_offset_t writeXRefTable(
trailer_e which, int first, int last, int size); trailer_e which,
qpdf_offset_t writeXRefTable( int first,
trailer_e which, int first, int last, int size, int last,
int size,
// for linearization // for linearization
qpdf_offset_t prev, qpdf_offset_t prev,
bool suppress_offsets, bool suppress_offsets,
@ -607,11 +667,21 @@ class QPDFWriter
qpdf_offset_t hint_length, qpdf_offset_t hint_length,
int linearization_pass); int linearization_pass);
qpdf_offset_t writeXRefStream( qpdf_offset_t writeXRefStream(
int objid, int max_id, qpdf_offset_t max_offset, int objid,
trailer_e which, int first, int last, int size); int max_id,
qpdf_offset_t max_offset,
trailer_e which,
int first,
int last,
int size);
qpdf_offset_t writeXRefStream( qpdf_offset_t writeXRefStream(
int objid, int max_id, qpdf_offset_t max_offset, int objid,
trailer_e which, int first, int last, int size, int max_id,
qpdf_offset_t max_offset,
trailer_e which,
int first,
int last,
int size,
// for linearization // for linearization
qpdf_offset_t prev, qpdf_offset_t prev,
int hint_id, int hint_id,
@ -627,7 +697,7 @@ class QPDFWriter
// popped. // popped.
Pipeline* pushPipeline(Pipeline*); Pipeline* pushPipeline(Pipeline*);
void activatePipelineStack(PipelinePopper&); void activatePipelineStack(PipelinePopper&);
void initializePipelineStack(Pipeline *); void initializePipelineStack(Pipeline*);
void adjustAESStreamLength(size_t& length); void adjustAESStreamLength(size_t& length);
void pushEncryptionFilter(PipelinePopper&); void pushEncryptionFilter(PipelinePopper&);
@ -635,8 +705,8 @@ class QPDFWriter
void pushMD5Pipeline(PipelinePopper&); void pushMD5Pipeline(PipelinePopper&);
void computeDeterministicIDData(); void computeDeterministicIDData();
void discardGeneration(std::map<QPDFObjGen, int> const& in, void discardGeneration(
std::map<int, int>& out); std::map<QPDFObjGen, int> const& in, std::map<int, int>& out);
class Members class Members
{ {
@ -681,8 +751,8 @@ class QPDFWriter
int encryption_V; int encryption_V;
int encryption_R; int encryption_R;
std::string id1; // for /ID key of std::string id1; // for /ID key of
std::string id2; // trailer dictionary std::string id2; // trailer dictionary
std::string final_pdf_version; std::string final_pdf_version;
int final_extension_level; int final_extension_level;
std::string min_pdf_version; std::string min_pdf_version;
@ -707,7 +777,7 @@ class QPDFWriter
std::map<QPDFObjGen, int> page_object_to_seq; std::map<QPDFObjGen, int> page_object_to_seq;
std::map<QPDFObjGen, int> contents_to_page_seq; std::map<QPDFObjGen, int> contents_to_page_seq;
std::map<QPDFObjGen, int> object_to_object_stream; std::map<QPDFObjGen, int> object_to_object_stream;
std::map<int, std::set<QPDFObjGen> > object_stream_to_objects; std::map<int, std::set<QPDFObjGen>> object_stream_to_objects;
std::list<Pipeline*> pipeline_stack; std::list<Pipeline*> pipeline_stack;
unsigned long long next_stack_id; unsigned long long next_stack_id;
bool deterministic_id; bool deterministic_id;

View File

@ -42,11 +42,11 @@ class QPDFXRefEntry
QPDF_DLL QPDF_DLL
int getType() const; int getType() const;
QPDF_DLL QPDF_DLL
qpdf_offset_t getOffset() const; // only for type 1 qpdf_offset_t getOffset() const; // only for type 1
QPDF_DLL QPDF_DLL
int getObjStreamNumber() const; // only for type 2 int getObjStreamNumber() const; // only for type 2
QPDF_DLL QPDF_DLL
int getObjStreamIndex() const; // only for type 2 int getObjStreamIndex() const; // only for type 2
private: private:
// This class does not use the Members pattern to avoid a memory // This class does not use the Members pattern to avoid a memory

View File

@ -28,6 +28,6 @@ namespace QTC
{ {
QPDF_DLL QPDF_DLL
void TC(char const* const scope, char const* const ccase, int n = 0); void TC(char const* const scope, char const* const ccase, int n = 0);
}; }; // namespace QTC
#endif // QTC_HH #endif // QTC_HH

View File

@ -23,16 +23,16 @@
#define QUTIL_HH #define QUTIL_HH
#include <qpdf/DLL.h> #include <qpdf/DLL.h>
#include <qpdf/Types.h>
#include <qpdf/PointerHolder.hh> #include <qpdf/PointerHolder.hh>
#include <string> #include <qpdf/Types.h>
#include <list>
#include <vector>
#include <stdexcept>
#include <functional> #include <functional>
#include <list>
#include <memory> #include <memory>
#include <stdexcept>
#include <stdio.h> #include <stdio.h>
#include <string>
#include <time.h> #include <time.h>
#include <vector>
class RandomDataProvider; class RandomDataProvider;
class Pipeline; class Pipeline;
@ -48,16 +48,16 @@ namespace QUtil
QPDF_DLL QPDF_DLL
std::string int_to_string_base(long long, int base, int length = 0); std::string int_to_string_base(long long, int base, int length = 0);
QPDF_DLL QPDF_DLL
std::string uint_to_string_base(unsigned long long, int base, std::string
int length = 0); uint_to_string_base(unsigned long long, int base, int length = 0);
QPDF_DLL QPDF_DLL
std::string double_to_string(double, int decimal_places = 0); std::string double_to_string(double, int decimal_places = 0);
// ABI: combine with other double_to_string by adding // ABI: combine with other double_to_string by adding
// trim_trailing_zeroes above as an optional parameter with a // trim_trailing_zeroes above as an optional parameter with a
// default of true. // default of true.
QPDF_DLL QPDF_DLL
std::string double_to_string(double, int decimal_places, std::string
bool trim_trailing_zeroes); double_to_string(double, int decimal_places, bool trim_trailing_zeroes);
// These string to number methods throw std::runtime_error on // These string to number methods throw std::runtime_error on
// underflow/overflow. // underflow/overflow.
@ -217,8 +217,14 @@ namespace QUtil
QPDFTime() = default; QPDFTime() = default;
QPDFTime(QPDFTime const&) = default; QPDFTime(QPDFTime const&) = default;
QPDFTime& operator=(QPDFTime const&) = default; QPDFTime& operator=(QPDFTime const&) = default;
QPDFTime(int year, int month, int day, int hour, QPDFTime(
int minute, int second, int tz_delta) : int year,
int month,
int day,
int hour,
int minute,
int second,
int tz_delta) :
year(year), year(year),
month(month), month(month),
day(day), day(day),
@ -228,13 +234,13 @@ namespace QUtil
tz_delta(tz_delta) tz_delta(tz_delta)
{ {
} }
int year; // actual year, no 1900 stuff int year; // actual year, no 1900 stuff
int month; // 1--12 int month; // 1--12
int day; // 1--31 int day; // 1--31
int hour; int hour;
int minute; int minute;
int second; int second;
int tz_delta; // minutes before UTC int tz_delta; // minutes before UTC
}; };
QPDF_DLL QPDF_DLL
@ -284,17 +290,16 @@ namespace QUtil
// encoding system by replacing all unsupported characters with // encoding system by replacing all unsupported characters with
// the given unknown_char. // the given unknown_char.
QPDF_DLL QPDF_DLL
std::string utf8_to_ascii( std::string utf8_to_ascii(std::string const& utf8, char unknown_char = '?');
std::string const& utf8, char unknown_char = '?');
QPDF_DLL QPDF_DLL
std::string utf8_to_win_ansi( std::string
std::string const& utf8, char unknown_char = '?'); utf8_to_win_ansi(std::string const& utf8, char unknown_char = '?');
QPDF_DLL QPDF_DLL
std::string utf8_to_mac_roman( std::string
std::string const& utf8, char unknown_char = '?'); utf8_to_mac_roman(std::string const& utf8, char unknown_char = '?');
QPDF_DLL QPDF_DLL
std::string utf8_to_pdf_doc( std::string
std::string const& utf8, char unknown_char = '?'); utf8_to_pdf_doc(std::string const& utf8, char unknown_char = '?');
// These versions return true if the conversion was successful and // These versions return true if the conversion was successful and
// false if any unrepresentable characters were found and had to // false if any unrepresentable characters were found and had to
@ -338,10 +343,11 @@ namespace QUtil
// the PDF spec requires UTF-16 to be UTF-16BE, qpdf (and just // the PDF spec requires UTF-16 to be UTF-16BE, qpdf (and just
// about everything else) accepts UTF-16LE (as of 10.6.2). // about everything else) accepts UTF-16LE (as of 10.6.2).
QPDF_DLL QPDF_DLL
void analyze_encoding(std::string const& str, void analyze_encoding(
bool& has_8bit_chars, std::string const& str,
bool& is_valid_utf8, bool& has_8bit_chars,
bool& is_utf16); bool& is_valid_utf8,
bool& is_utf16);
// Try to compensate for previously incorrectly encoded strings. // Try to compensate for previously incorrectly encoded strings.
// We want to compensate for the following errors: // We want to compensate for the following errors:
@ -398,14 +404,14 @@ namespace QUtil
// Filename is UTF-8 encoded, even on Windows, as described in the // Filename is UTF-8 encoded, even on Windows, as described in the
// comments for safe_fopen. // comments for safe_fopen.
QPDF_DLL QPDF_DLL
std::list<std::string> read_lines_from_file( std::list<std::string>
char const* filename, bool preserve_eol = false); read_lines_from_file(char const* filename, bool preserve_eol = false);
QPDF_DLL QPDF_DLL
std::list<std::string> read_lines_from_file( std::list<std::string>
std::istream&, bool preserve_eol = false); read_lines_from_file(std::istream&, bool preserve_eol = false);
QPDF_DLL QPDF_DLL
std::list<std::string> read_lines_from_file( std::list<std::string>
FILE*, bool preserve_eol = false); read_lines_from_file(FILE*, bool preserve_eol = false);
QPDF_DLL QPDF_DLL
void read_lines_from_file( void read_lines_from_file(
std::function<bool(char&)> next_char, std::function<bool(char&)> next_char,
@ -420,7 +426,7 @@ namespace QUtil
// platforms, so we have to give it a name that is not likely to // platforms, so we have to give it a name that is not likely to
// be a macro anywhere. // be a macro anywhere.
QPDF_DLL QPDF_DLL
int str_compare_nocase(char const *, char const *); int str_compare_nocase(char const*, char const*);
// These routines help the tokenizer recognize certain character // These routines help the tokenizer recognize certain character
// classes without using ctype, which we avoid because of locale // classes without using ctype, which we avoid because of locale
@ -454,13 +460,13 @@ namespace QUtil
// another main. // another main.
QPDF_DLL QPDF_DLL
int call_main_from_wmain( int call_main_from_wmain(
int argc, wchar_t* argv[], int argc, wchar_t* argv[], std::function<int(int, char*[])> realmain);
std::function<int(int, char*[])> realmain);
QPDF_DLL QPDF_DLL
int call_main_from_wmain( int call_main_from_wmain(
int argc, wchar_t const* const argv[], int argc,
wchar_t const* const argv[],
std::function<int(int, char const* const[])> realmain); std::function<int(int, char const* const[])> realmain);
#endif // QPDF_NO_WCHAR_T #endif // QPDF_NO_WCHAR_T
}; }; // namespace QUtil
#endif // QUTIL_HH #endif // QUTIL_HH

View File

@ -137,9 +137,9 @@
* https://github.com/qpdf/qpdf/issues/new. * https://github.com/qpdf/qpdf/issues/new.
*/ */
#include <qpdf/Constants.h>
#include <qpdf/DLL.h> #include <qpdf/DLL.h>
#include <qpdf/Types.h> #include <qpdf/Types.h>
#include <qpdf/Constants.h>
#include <string.h> #include <string.h>
#ifdef __cplusplus #ifdef __cplusplus
@ -154,13 +154,13 @@ extern "C" {
* that the values below can be logically orred together. * that the values below can be logically orred together.
*/ */
typedef int QPDF_ERROR_CODE; typedef int QPDF_ERROR_CODE;
# define QPDF_SUCCESS 0 #define QPDF_SUCCESS 0
# define QPDF_WARNINGS 1 << 0 #define QPDF_WARNINGS 1 << 0
# define QPDF_ERRORS 1 << 1 #define QPDF_ERRORS 1 << 1
typedef int QPDF_BOOL; typedef int QPDF_BOOL;
# define QPDF_TRUE 1 #define QPDF_TRUE 1
# define QPDF_FALSE 0 #define QPDF_FALSE 0
/* From qpdf 10.5: call this method to signal to the library that /* From qpdf 10.5: call this method to signal to the library that
* you are explicitly handling errors from functions that don't * you are explicitly handling errors from functions that don't
@ -273,8 +273,8 @@ extern "C" {
* pointer or an empty string as the password. * pointer or an empty string as the password.
*/ */
QPDF_DLL QPDF_DLL
QPDF_ERROR_CODE qpdf_read(qpdf_data qpdf, char const* filename, QPDF_ERROR_CODE
char const* password); qpdf_read(qpdf_data qpdf, char const* filename, char const* password);
/* Calling qpdf_read_memory causes processMemoryFile to be called /* Calling qpdf_read_memory causes processMemoryFile to be called
* in the C++ API. Otherwise, it behaves in the same way as * in the C++ API. Otherwise, it behaves in the same way as
@ -283,11 +283,12 @@ extern "C" {
* library. * library.
*/ */
QPDF_DLL QPDF_DLL
QPDF_ERROR_CODE qpdf_read_memory(qpdf_data qpdf, QPDF_ERROR_CODE qpdf_read_memory(
char const* description, qpdf_data qpdf,
char const* buffer, char const* description,
unsigned long long size, char const* buffer,
char const* password); unsigned long long size,
char const* password);
/* Calling qpdf_empty_pdf initializes this qpdf object with an /* Calling qpdf_empty_pdf initializes this qpdf object with an
* empty PDF, making it possible to create a PDF from scratch * empty PDF, making it possible to create a PDF from scratch
@ -409,24 +410,23 @@ extern "C" {
unsigned char const* qpdf_get_buffer(qpdf_data qpdf); unsigned char const* qpdf_get_buffer(qpdf_data qpdf);
QPDF_DLL QPDF_DLL
void qpdf_set_object_stream_mode(qpdf_data qpdf, void
enum qpdf_object_stream_e mode); qpdf_set_object_stream_mode(qpdf_data qpdf, enum qpdf_object_stream_e mode);
QPDF_DLL QPDF_DLL
void qpdf_set_stream_data_mode(qpdf_data qpdf, void
enum qpdf_stream_data_e mode); qpdf_set_stream_data_mode(qpdf_data qpdf, enum qpdf_stream_data_e mode);
QPDF_DLL QPDF_DLL
void qpdf_set_compress_streams(qpdf_data qpdf, QPDF_BOOL value); void qpdf_set_compress_streams(qpdf_data qpdf, QPDF_BOOL value);
QPDF_DLL
void qpdf_set_decode_level(
qpdf_data qpdf, enum qpdf_stream_decode_level_e level);
QPDF_DLL QPDF_DLL
void qpdf_set_decode_level(qpdf_data qpdf, void
enum qpdf_stream_decode_level_e level); qpdf_set_preserve_unreferenced_objects(qpdf_data qpdf, QPDF_BOOL value);
QPDF_DLL
void qpdf_set_preserve_unreferenced_objects(
qpdf_data qpdf, QPDF_BOOL value);
QPDF_DLL QPDF_DLL
void qpdf_set_newline_before_endstream(qpdf_data qpdf, QPDF_BOOL value); void qpdf_set_newline_before_endstream(qpdf_data qpdf, QPDF_BOOL value);
@ -453,77 +453,120 @@ extern "C" {
void qpdf_set_static_aes_IV(qpdf_data qpdf, QPDF_BOOL value); void qpdf_set_static_aes_IV(qpdf_data qpdf, QPDF_BOOL value);
QPDF_DLL QPDF_DLL
void qpdf_set_suppress_original_object_IDs( void qpdf_set_suppress_original_object_IDs(qpdf_data qpdf, QPDF_BOOL value);
qpdf_data qpdf, QPDF_BOOL value);
QPDF_DLL QPDF_DLL
void qpdf_set_preserve_encryption(qpdf_data qpdf, QPDF_BOOL value); void qpdf_set_preserve_encryption(qpdf_data qpdf, QPDF_BOOL value);
QPDF_DLL QPDF_DLL
void qpdf_set_r2_encryption_parameters( void qpdf_set_r2_encryption_parameters(
qpdf_data qpdf, char const* user_password, char const* owner_password, qpdf_data qpdf,
QPDF_BOOL allow_print, QPDF_BOOL allow_modify, char const* user_password,
QPDF_BOOL allow_extract, QPDF_BOOL allow_annotate); char const* owner_password,
QPDF_BOOL allow_print,
QPDF_BOOL allow_modify,
QPDF_BOOL allow_extract,
QPDF_BOOL allow_annotate);
QPDF_DLL QPDF_DLL
void qpdf_set_r3_encryption_parameters2( void qpdf_set_r3_encryption_parameters2(
qpdf_data qpdf, char const* user_password, char const* owner_password, qpdf_data qpdf,
QPDF_BOOL allow_accessibility, QPDF_BOOL allow_extract, char const* user_password,
QPDF_BOOL allow_assemble, QPDF_BOOL allow_annotate_and_form, char const* owner_password,
QPDF_BOOL allow_form_filling, QPDF_BOOL allow_modify_other, QPDF_BOOL allow_accessibility,
QPDF_BOOL allow_extract,
QPDF_BOOL allow_assemble,
QPDF_BOOL allow_annotate_and_form,
QPDF_BOOL allow_form_filling,
QPDF_BOOL allow_modify_other,
enum qpdf_r3_print_e print); enum qpdf_r3_print_e print);
QPDF_DLL QPDF_DLL
void qpdf_set_r4_encryption_parameters2( void qpdf_set_r4_encryption_parameters2(
qpdf_data qpdf, char const* user_password, char const* owner_password, qpdf_data qpdf,
QPDF_BOOL allow_accessibility, QPDF_BOOL allow_extract, char const* user_password,
QPDF_BOOL allow_assemble, QPDF_BOOL allow_annotate_and_form, char const* owner_password,
QPDF_BOOL allow_form_filling, QPDF_BOOL allow_modify_other, QPDF_BOOL allow_accessibility,
QPDF_BOOL allow_extract,
QPDF_BOOL allow_assemble,
QPDF_BOOL allow_annotate_and_form,
QPDF_BOOL allow_form_filling,
QPDF_BOOL allow_modify_other,
enum qpdf_r3_print_e print, enum qpdf_r3_print_e print,
QPDF_BOOL encrypt_metadata, QPDF_BOOL use_aes); QPDF_BOOL encrypt_metadata,
QPDF_BOOL use_aes);
QPDF_DLL QPDF_DLL
void qpdf_set_r5_encryption_parameters2( void qpdf_set_r5_encryption_parameters2(
qpdf_data qpdf, char const* user_password, char const* owner_password, qpdf_data qpdf,
QPDF_BOOL allow_accessibility, QPDF_BOOL allow_extract, char const* user_password,
QPDF_BOOL allow_assemble, QPDF_BOOL allow_annotate_and_form, char const* owner_password,
QPDF_BOOL allow_form_filling, QPDF_BOOL allow_modify_other, QPDF_BOOL allow_accessibility,
enum qpdf_r3_print_e print, QPDF_BOOL encrypt_metadata); QPDF_BOOL allow_extract,
QPDF_BOOL allow_assemble,
QPDF_BOOL allow_annotate_and_form,
QPDF_BOOL allow_form_filling,
QPDF_BOOL allow_modify_other,
enum qpdf_r3_print_e print,
QPDF_BOOL encrypt_metadata);
QPDF_DLL QPDF_DLL
void qpdf_set_r6_encryption_parameters2( void qpdf_set_r6_encryption_parameters2(
qpdf_data qpdf, char const* user_password, char const* owner_password, qpdf_data qpdf,
QPDF_BOOL allow_accessibility, QPDF_BOOL allow_extract, char const* user_password,
QPDF_BOOL allow_assemble, QPDF_BOOL allow_annotate_and_form, char const* owner_password,
QPDF_BOOL allow_form_filling, QPDF_BOOL allow_modify_other, QPDF_BOOL allow_accessibility,
enum qpdf_r3_print_e print, QPDF_BOOL encrypt_metadata); QPDF_BOOL allow_extract,
QPDF_BOOL allow_assemble,
QPDF_BOOL allow_annotate_and_form,
QPDF_BOOL allow_form_filling,
QPDF_BOOL allow_modify_other,
enum qpdf_r3_print_e print,
QPDF_BOOL encrypt_metadata);
/* Pre 8.4.0 encryption API */ /* Pre 8.4.0 encryption API */
QPDF_DLL QPDF_DLL
void qpdf_set_r3_encryption_parameters( void qpdf_set_r3_encryption_parameters(
qpdf_data qpdf, char const* user_password, char const* owner_password, qpdf_data qpdf,
QPDF_BOOL allow_accessibility, QPDF_BOOL allow_extract, char const* user_password,
enum qpdf_r3_print_e print, enum qpdf_r3_modify_e modify); char const* owner_password,
QPDF_BOOL allow_accessibility,
QPDF_BOOL allow_extract,
enum qpdf_r3_print_e print,
enum qpdf_r3_modify_e modify);
QPDF_DLL QPDF_DLL
void qpdf_set_r4_encryption_parameters( void qpdf_set_r4_encryption_parameters(
qpdf_data qpdf, char const* user_password, char const* owner_password, qpdf_data qpdf,
QPDF_BOOL allow_accessibility, QPDF_BOOL allow_extract, char const* user_password,
enum qpdf_r3_print_e print, enum qpdf_r3_modify_e modify, char const* owner_password,
QPDF_BOOL encrypt_metadata, QPDF_BOOL use_aes); QPDF_BOOL allow_accessibility,
QPDF_BOOL allow_extract,
enum qpdf_r3_print_e print,
enum qpdf_r3_modify_e modify,
QPDF_BOOL encrypt_metadata,
QPDF_BOOL use_aes);
QPDF_DLL QPDF_DLL
void qpdf_set_r5_encryption_parameters( void qpdf_set_r5_encryption_parameters(
qpdf_data qpdf, char const* user_password, char const* owner_password, qpdf_data qpdf,
QPDF_BOOL allow_accessibility, QPDF_BOOL allow_extract, char const* user_password,
enum qpdf_r3_print_e print, enum qpdf_r3_modify_e modify, char const* owner_password,
QPDF_BOOL allow_accessibility,
QPDF_BOOL allow_extract,
enum qpdf_r3_print_e print,
enum qpdf_r3_modify_e modify,
QPDF_BOOL encrypt_metadata); QPDF_BOOL encrypt_metadata);
QPDF_DLL QPDF_DLL
void qpdf_set_r6_encryption_parameters( void qpdf_set_r6_encryption_parameters(
qpdf_data qpdf, char const* user_password, char const* owner_password, qpdf_data qpdf,
QPDF_BOOL allow_accessibility, QPDF_BOOL allow_extract, char const* user_password,
enum qpdf_r3_print_e print, enum qpdf_r3_modify_e modify, char const* owner_password,
QPDF_BOOL allow_accessibility,
QPDF_BOOL allow_extract,
enum qpdf_r3_print_e print,
enum qpdf_r3_modify_e modify,
QPDF_BOOL encrypt_metadata); QPDF_BOOL encrypt_metadata);
QPDF_DLL QPDF_DLL
@ -648,8 +691,8 @@ extern "C" {
QPDF_DLL QPDF_DLL
qpdf_oh qpdf_make_indirect_object(qpdf_data qpdf, qpdf_oh oh); qpdf_oh qpdf_make_indirect_object(qpdf_data qpdf, qpdf_oh oh);
QPDF_DLL QPDF_DLL
void qpdf_replace_object( void
qpdf_data qpdf, int objid, int generation, qpdf_oh oh); qpdf_replace_object(qpdf_data qpdf, int objid, int generation, qpdf_oh oh);
/* Wrappers around QPDFObjectHandle methods. Be sure to read /* Wrappers around QPDFObjectHandle methods. Be sure to read
* corresponding comments in QPDFObjectHandle.hh to understand * corresponding comments in QPDFObjectHandle.hh to understand
@ -690,8 +733,8 @@ extern "C" {
QPDF_BOOL qpdf_oh_is_scalar(qpdf_data qpdf, qpdf_oh oh); QPDF_BOOL qpdf_oh_is_scalar(qpdf_data qpdf, qpdf_oh oh);
QPDF_DLL QPDF_DLL
QPDF_BOOL qpdf_oh_is_name_and_equals( QPDF_BOOL
qpdf_data qpdf, qpdf_oh oh, char const* name); qpdf_oh_is_name_and_equals(qpdf_data qpdf, qpdf_oh oh, char const* name);
QPDF_DLL QPDF_DLL
QPDF_BOOL qpdf_oh_is_dictionary_of_type( QPDF_BOOL qpdf_oh_is_dictionary_of_type(
@ -711,19 +754,18 @@ extern "C" {
QPDF_DLL QPDF_DLL
QPDF_BOOL qpdf_oh_get_bool_value(qpdf_data qpdf, qpdf_oh oh); QPDF_BOOL qpdf_oh_get_bool_value(qpdf_data qpdf, qpdf_oh oh);
QPDF_DLL QPDF_DLL
QPDF_BOOL qpdf_oh_get_value_as_bool( QPDF_BOOL
qpdf_data qpdf, qpdf_oh oh, QPDF_BOOL* value); qpdf_oh_get_value_as_bool(qpdf_data qpdf, qpdf_oh oh, QPDF_BOOL* value);
QPDF_DLL QPDF_DLL
long long qpdf_oh_get_int_value(qpdf_data qpdf, qpdf_oh oh); long long qpdf_oh_get_int_value(qpdf_data qpdf, qpdf_oh oh);
QPDF_DLL QPDF_DLL
QPDF_BOOL qpdf_oh_get_value_as_longlong( QPDF_BOOL
qpdf_data qpdf, qpdf_oh oh, long long* value); qpdf_oh_get_value_as_longlong(qpdf_data qpdf, qpdf_oh oh, long long* value);
QPDF_DLL QPDF_DLL
int qpdf_oh_get_int_value_as_int(qpdf_data qpdf, qpdf_oh oh); int qpdf_oh_get_int_value_as_int(qpdf_data qpdf, qpdf_oh oh);
QPDF_DLL QPDF_DLL
QPDF_BOOL qpdf_oh_get_value_as_int( QPDF_BOOL qpdf_oh_get_value_as_int(qpdf_data qpdf, qpdf_oh oh, int* value);
qpdf_data qpdf, qpdf_oh oh, int* value);
QPDF_DLL QPDF_DLL
unsigned long long qpdf_oh_get_uint_value(qpdf_data qpdf, qpdf_oh oh); unsigned long long qpdf_oh_get_uint_value(qpdf_data qpdf, qpdf_oh oh);
QPDF_DLL QPDF_DLL
@ -732,8 +774,8 @@ extern "C" {
QPDF_DLL QPDF_DLL
unsigned int qpdf_oh_get_uint_value_as_uint(qpdf_data qpdf, qpdf_oh oh); unsigned int qpdf_oh_get_uint_value_as_uint(qpdf_data qpdf, qpdf_oh oh);
QPDF_DLL QPDF_DLL
QPDF_BOOL qpdf_oh_get_value_as_uint( QPDF_BOOL
qpdf_data qpdf, qpdf_oh oh, unsigned int* value); qpdf_oh_get_value_as_uint(qpdf_data qpdf, qpdf_oh oh, unsigned int* value);
QPDF_DLL QPDF_DLL
char const* qpdf_oh_get_real_value(qpdf_data qpdf, qpdf_oh oh); char const* qpdf_oh_get_real_value(qpdf_data qpdf, qpdf_oh oh);
@ -746,8 +788,8 @@ extern "C" {
QPDF_DLL QPDF_DLL
double qpdf_oh_get_numeric_value(qpdf_data qpdf, qpdf_oh oh); double qpdf_oh_get_numeric_value(qpdf_data qpdf, qpdf_oh oh);
QPDF_DLL QPDF_DLL
QPDF_BOOL qpdf_oh_get_value_as_number( QPDF_BOOL
qpdf_data qpdf, qpdf_oh oh, double* value); qpdf_oh_get_value_as_number(qpdf_data qpdf, qpdf_oh oh, double* value);
QPDF_DLL QPDF_DLL
char const* qpdf_oh_get_name(qpdf_data qpdf, qpdf_oh oh); char const* qpdf_oh_get_name(qpdf_data qpdf, qpdf_oh oh);
@ -782,11 +824,11 @@ extern "C" {
QPDF_BOOL qpdf_oh_get_value_as_utf8( QPDF_BOOL qpdf_oh_get_value_as_utf8(
qpdf_data qpdf, qpdf_oh oh, char const** value, size_t* length); qpdf_data qpdf, qpdf_oh oh, char const** value, size_t* length);
QPDF_DLL QPDF_DLL
char const* qpdf_oh_get_binary_string_value( char const*
qpdf_data qpdf, qpdf_oh oh, size_t* length); qpdf_oh_get_binary_string_value(qpdf_data qpdf, qpdf_oh oh, size_t* length);
QPDF_DLL QPDF_DLL
char const* qpdf_oh_get_binary_utf8_value( char const*
qpdf_data qpdf, qpdf_oh oh, size_t* length); qpdf_oh_get_binary_utf8_value(qpdf_data qpdf, qpdf_oh oh, size_t* length);
QPDF_DLL QPDF_DLL
int qpdf_oh_get_array_n_items(qpdf_data qpdf, qpdf_oh oh); int qpdf_oh_get_array_n_items(qpdf_data qpdf, qpdf_oh oh);
@ -822,12 +864,12 @@ extern "C" {
QPDF_DLL QPDF_DLL
qpdf_oh qpdf_oh_get_key(qpdf_data qpdf, qpdf_oh oh, char const* key); qpdf_oh qpdf_oh_get_key(qpdf_data qpdf, qpdf_oh oh, char const* key);
QPDF_DLL QPDF_DLL
qpdf_oh qpdf_oh_get_key_if_dict( qpdf_oh
qpdf_data qpdf, qpdf_oh oh, char const* key); qpdf_oh_get_key_if_dict(qpdf_data qpdf, qpdf_oh oh, char const* key);
QPDF_DLL QPDF_DLL
QPDF_BOOL qpdf_oh_is_or_has_name( QPDF_BOOL
qpdf_data qpdf, qpdf_oh oh, char const* key); qpdf_oh_is_or_has_name(qpdf_data qpdf, qpdf_oh oh, char const* key);
QPDF_DLL QPDF_DLL
qpdf_oh qpdf_oh_new_uninitialized(qpdf_data qpdf); qpdf_oh qpdf_oh_new_uninitialized(qpdf_data qpdf);
@ -840,8 +882,8 @@ extern "C" {
QPDF_DLL QPDF_DLL
qpdf_oh qpdf_oh_new_real_from_string(qpdf_data qpdf, char const* value); qpdf_oh qpdf_oh_new_real_from_string(qpdf_data qpdf, char const* value);
QPDF_DLL QPDF_DLL
qpdf_oh qpdf_oh_new_real_from_double(qpdf_data qpdf, qpdf_oh qpdf_oh_new_real_from_double(
double value, int decimal_places); qpdf_data qpdf, double value, int decimal_places);
QPDF_DLL QPDF_DLL
qpdf_oh qpdf_oh_new_name(qpdf_data qpdf, char const* name); qpdf_oh qpdf_oh_new_name(qpdf_data qpdf, char const* name);
QPDF_DLL QPDF_DLL
@ -852,9 +894,9 @@ extern "C" {
* contain atrbitary binary data including embedded null characters. * contain atrbitary binary data including embedded null characters.
*/ */
QPDF_DLL QPDF_DLL
qpdf_oh qpdf_oh_new_binary_string( qpdf_oh
qpdf_data qpdf, char const* str, size_t length); qpdf_oh_new_binary_string(qpdf_data qpdf, char const* str, size_t length);
QPDF_DLL QPDF_DLL
qpdf_oh qpdf_oh_new_binary_unicode_string( qpdf_oh qpdf_oh_new_binary_unicode_string(
qpdf_data qpdf, char const* str, size_t length); qpdf_data qpdf, char const* str, size_t length);
QPDF_DLL QPDF_DLL
@ -867,7 +909,7 @@ extern "C" {
* comments in QPDFObjectHandle.hh for newStream() for additional * comments in QPDFObjectHandle.hh for newStream() for additional
* notes. You must call qpdf_oh_replace_stream_data to provide * notes. You must call qpdf_oh_replace_stream_data to provide
* data for the stream. See STREAM FUNCTIONS below. * data for the stream. See STREAM FUNCTIONS below.
*/ */
QPDF_DLL QPDF_DLL
qpdf_oh qpdf_oh_new_stream(qpdf_data qpdf); qpdf_oh qpdf_oh_new_stream(qpdf_data qpdf);
@ -875,8 +917,8 @@ extern "C" {
void qpdf_oh_make_direct(qpdf_data qpdf, qpdf_oh oh); void qpdf_oh_make_direct(qpdf_data qpdf, qpdf_oh oh);
QPDF_DLL QPDF_DLL
void qpdf_oh_set_array_item(qpdf_data qpdf, qpdf_oh oh, void
int at, qpdf_oh item); qpdf_oh_set_array_item(qpdf_data qpdf, qpdf_oh oh, int at, qpdf_oh item);
QPDF_DLL QPDF_DLL
void qpdf_oh_insert_item(qpdf_data qpdf, qpdf_oh oh, int at, qpdf_oh item); void qpdf_oh_insert_item(qpdf_data qpdf, qpdf_oh oh, int at, qpdf_oh item);
QPDF_DLL QPDF_DLL
@ -885,13 +927,13 @@ extern "C" {
void qpdf_oh_erase_item(qpdf_data qpdf, qpdf_oh oh, int at); void qpdf_oh_erase_item(qpdf_data qpdf, qpdf_oh oh, int at);
QPDF_DLL QPDF_DLL
void qpdf_oh_replace_key(qpdf_data qpdf, qpdf_oh oh, void qpdf_oh_replace_key(
char const* key, qpdf_oh item); qpdf_data qpdf, qpdf_oh oh, char const* key, qpdf_oh item);
QPDF_DLL QPDF_DLL
void qpdf_oh_remove_key(qpdf_data qpdf, qpdf_oh oh, char const* key); void qpdf_oh_remove_key(qpdf_data qpdf, qpdf_oh oh, char const* key);
QPDF_DLL QPDF_DLL
void qpdf_oh_replace_or_remove_key(qpdf_data qpdf, qpdf_oh oh, void qpdf_oh_replace_or_remove_key(
char const* key, qpdf_oh item); qpdf_data qpdf, qpdf_oh oh, char const* key, qpdf_oh item);
QPDF_DLL QPDF_DLL
qpdf_oh qpdf_oh_get_dict(qpdf_data qpdf, qpdf_oh oh); qpdf_oh qpdf_oh_get_dict(qpdf_data qpdf, qpdf_oh oh);
@ -946,9 +988,12 @@ extern "C" {
*/ */
QPDF_DLL QPDF_DLL
QPDF_ERROR_CODE qpdf_oh_get_stream_data( QPDF_ERROR_CODE qpdf_oh_get_stream_data(
qpdf_data qpdf, qpdf_oh stream_oh, qpdf_data qpdf,
enum qpdf_stream_decode_level_e decode_level, QPDF_BOOL* filtered, qpdf_oh stream_oh,
unsigned char** bufp, size_t* len); enum qpdf_stream_decode_level_e decode_level,
QPDF_BOOL* filtered,
unsigned char** bufp,
size_t* len);
/* This function returns the concatenation of all of a page's /* This function returns the concatenation of all of a page's
* content streams as a single, dynamically allocated buffer. As * content streams as a single, dynamically allocated buffer. As
@ -957,17 +1002,19 @@ extern "C" {
*/ */
QPDF_DLL QPDF_DLL
QPDF_ERROR_CODE qpdf_oh_get_page_content_data( QPDF_ERROR_CODE qpdf_oh_get_page_content_data(
qpdf_data qpdf, qpdf_oh page_oh, qpdf_data qpdf, qpdf_oh page_oh, unsigned char** bufp, size_t* len);
unsigned char** bufp, size_t* len);
/* The data pointed to by bufp will be copied by the library. It /* The data pointed to by bufp will be copied by the library. It
* does not need to remain valid after the call returns. * does not need to remain valid after the call returns.
*/ */
QPDF_DLL QPDF_DLL
void qpdf_oh_replace_stream_data( void qpdf_oh_replace_stream_data(
qpdf_data qpdf, qpdf_oh stream_oh, qpdf_data qpdf,
unsigned char const* buf, size_t len, qpdf_oh stream_oh,
qpdf_oh filter, qpdf_oh decode_parms); unsigned char const* buf,
size_t len,
qpdf_oh filter,
qpdf_oh decode_parms);
/* PAGE FUNCTIONS */ /* PAGE FUNCTIONS */
@ -1018,14 +1065,17 @@ extern "C" {
QPDF_DLL QPDF_DLL
QPDF_ERROR_CODE qpdf_add_page( QPDF_ERROR_CODE qpdf_add_page(
qpdf_data qpdf, qpdf_data qpdf,
qpdf_data newpage_qpdf, qpdf_oh newpage, qpdf_data newpage_qpdf,
qpdf_oh newpage,
QPDF_BOOL first); QPDF_BOOL first);
/* addPageAt() */ /* addPageAt() */
QPDF_DLL QPDF_DLL
QPDF_ERROR_CODE qpdf_add_page_at( QPDF_ERROR_CODE qpdf_add_page_at(
qpdf_data qpdf, qpdf_data qpdf,
qpdf_data newpage_qpdf, qpdf_oh newpage, qpdf_data newpage_qpdf,
QPDF_BOOL before, qpdf_oh refpage); qpdf_oh newpage,
QPDF_BOOL before,
qpdf_oh refpage);
/* removePage() */ /* removePage() */
QPDF_DLL QPDF_DLL
QPDF_ERROR_CODE qpdf_remove_page(qpdf_data qpdf, qpdf_oh page); QPDF_ERROR_CODE qpdf_remove_page(qpdf_data qpdf, qpdf_oh page);
@ -1033,5 +1083,4 @@ extern "C" {
} }
#endif #endif
#endif /* QPDF_C_H */ #endif /* QPDF_C_H */

View File

@ -75,5 +75,4 @@ extern "C" {
} }
#endif #endif
#endif /* QPDFJOB_C_H */ #endif /* QPDFJOB_C_H */

View File

@ -1,18 +1,21 @@
#include <qpdf/AES_PDF_native.hh> #include <qpdf/AES_PDF_native.hh>
#include <qpdf/QUtil.hh>
#include <cstring>
#include <assert.h>
#include <stdexcept>
#include <qpdf/rijndael.h>
#include <qpdf/QIntC.hh> #include <qpdf/QIntC.hh>
#include <string>
#include <stdlib.h>
#include <qpdf/QPDFCryptoImpl.hh> #include <qpdf/QPDFCryptoImpl.hh>
#include <qpdf/QUtil.hh>
#include <qpdf/rijndael.h>
#include <assert.h>
#include <cstring>
#include <stdexcept>
#include <stdlib.h>
#include <string>
AES_PDF_native::AES_PDF_native(bool encrypt, unsigned char const* key, AES_PDF_native::AES_PDF_native(
size_t key_bytes, bool cbc_mode, bool encrypt,
unsigned char* cbc_block) : unsigned char const* key,
size_t key_bytes,
bool cbc_mode,
unsigned char* cbc_block) :
encrypt(encrypt), encrypt(encrypt),
cbc_mode(cbc_mode), cbc_mode(cbc_mode),
cbc_block(cbc_block), cbc_block(cbc_block),
@ -24,15 +27,12 @@ AES_PDF_native::AES_PDF_native(bool encrypt, unsigned char const* key,
size_t rk_bytes = RKLENGTH(keybits) * sizeof(uint32_t); size_t rk_bytes = RKLENGTH(keybits) * sizeof(uint32_t);
std::memcpy(this->key.get(), key, key_bytes); std::memcpy(this->key.get(), key, key_bytes);
std::memset(this->rk.get(), 0, rk_bytes); std::memset(this->rk.get(), 0, rk_bytes);
if (encrypt) if (encrypt) {
{ this->nrounds =
this->nrounds = rijndaelSetupEncrypt( rijndaelSetupEncrypt(this->rk.get(), this->key.get(), keybits);
this->rk.get(), this->key.get(), keybits); } else {
} this->nrounds =
else rijndaelSetupDecrypt(this->rk.get(), this->key.get(), keybits);
{
this->nrounds = rijndaelSetupDecrypt(
this->rk.get(), this->key.get(), keybits);
} }
} }
@ -43,35 +43,24 @@ AES_PDF_native::~AES_PDF_native()
void void
AES_PDF_native::update(unsigned char* in_data, unsigned char* out_data) AES_PDF_native::update(unsigned char* in_data, unsigned char* out_data)
{ {
if (this->encrypt) if (this->encrypt) {
{ if (this->cbc_mode) {
if (this->cbc_mode) for (size_t i = 0; i < QPDFCryptoImpl::rijndael_buf_size; ++i) {
{
for (size_t i = 0; i < QPDFCryptoImpl::rijndael_buf_size; ++i)
{
in_data[i] ^= this->cbc_block[i]; in_data[i] ^= this->cbc_block[i];
} }
} }
rijndaelEncrypt(this->rk.get(), rijndaelEncrypt(this->rk.get(), this->nrounds, in_data, out_data);
this->nrounds, in_data, out_data); if (this->cbc_mode) {
if (this->cbc_mode) memcpy(
{ this->cbc_block, out_data, QPDFCryptoImpl::rijndael_buf_size);
memcpy(this->cbc_block, out_data,
QPDFCryptoImpl::rijndael_buf_size);
} }
} } else {
else rijndaelDecrypt(this->rk.get(), this->nrounds, in_data, out_data);
{ if (this->cbc_mode) {
rijndaelDecrypt(this->rk.get(), for (size_t i = 0; i < QPDFCryptoImpl::rijndael_buf_size; ++i) {
this->nrounds, in_data, out_data);
if (this->cbc_mode)
{
for (size_t i = 0; i < QPDFCryptoImpl::rijndael_buf_size; ++i)
{
out_data[i] ^= this->cbc_block[i]; out_data[i] ^= this->cbc_block[i];
} }
memcpy(this->cbc_block, in_data, memcpy(this->cbc_block, in_data, QPDFCryptoImpl::rijndael_buf_size);
QPDFCryptoImpl::rijndael_buf_size);
} }
} }
} }

View File

@ -18,8 +18,7 @@ BitStream::reset()
{ {
p = start; p = start;
bit_offset = 7; bit_offset = 7;
if (QIntC::to_uint(nbytes) > static_cast<unsigned int>(-1) / 8) if (QIntC::to_uint(nbytes) > static_cast<unsigned int>(-1) / 8) {
{
throw std::runtime_error("array too large for bitstream"); throw std::runtime_error("array too large for bitstream");
} }
bits_available = 8 * nbytes; bits_available = 8 * nbytes;
@ -28,22 +27,18 @@ BitStream::reset()
unsigned long long unsigned long long
BitStream::getBits(size_t nbits) BitStream::getBits(size_t nbits)
{ {
return read_bits(this->p, this->bit_offset, return read_bits(this->p, this->bit_offset, this->bits_available, nbits);
this->bits_available, nbits);
} }
long long long long
BitStream::getBitsSigned(size_t nbits) BitStream::getBitsSigned(size_t nbits)
{ {
unsigned long long bits = read_bits(this->p, this->bit_offset, unsigned long long bits =
this->bits_available, nbits); read_bits(this->p, this->bit_offset, this->bits_available, nbits);
long long result = 0; long long result = 0;
if (static_cast<long long>(bits) > 1LL << (nbits - 1)) if (static_cast<long long>(bits) > 1LL << (nbits - 1)) {
{ result = static_cast<long long>(bits - (1ULL << nbits));
result = static_cast<long long>(bits -(1ULL << nbits)); } else {
}
else
{
result = static_cast<long long>(bits); result = static_cast<long long>(bits);
} }
return result; return result;
@ -52,20 +47,16 @@ BitStream::getBitsSigned(size_t nbits)
int int
BitStream::getBitsInt(size_t nbits) BitStream::getBitsInt(size_t nbits)
{ {
return static_cast<int>( return static_cast<int>(QIntC::to_uint(
QIntC::to_uint( read_bits(this->p, this->bit_offset, this->bits_available, nbits)));
read_bits(this->p, this->bit_offset,
this->bits_available, nbits)));
} }
void void
BitStream::skipToNextByte() BitStream::skipToNextByte()
{ {
if (bit_offset != 7) if (bit_offset != 7) {
{
size_t bits_to_skip = bit_offset + 1; size_t bits_to_skip = bit_offset + 1;
if (bits_available < bits_to_skip) if (bits_available < bits_to_skip) {
{
throw std::logic_error( throw std::logic_error(
"INTERNAL ERROR: overflow skipping to next byte in bitstream"); "INTERNAL ERROR: overflow skipping to next byte in bitstream");
} }

View File

@ -21,12 +21,9 @@ void
BitWriter::writeBitsSigned(long long val, size_t bits) BitWriter::writeBitsSigned(long long val, size_t bits)
{ {
unsigned long long uval = 0; unsigned long long uval = 0;
if (val < 0) if (val < 0) {
{
uval = (1ULL << bits) + static_cast<unsigned long long>(val); uval = (1ULL << bits) + static_cast<unsigned long long>(val);
} } else {
else
{
uval = static_cast<unsigned long long>(val); uval = static_cast<unsigned long long>(val);
} }
writeBits(uval, bits); writeBits(uval, bits);
@ -41,8 +38,7 @@ BitWriter::writeBitsInt(int val, size_t bits)
void void
BitWriter::flush() BitWriter::flush()
{ {
if (bit_offset < 7) if (bit_offset < 7) {
{
size_t bits_to_write = bit_offset + 1; size_t bits_to_write = bit_offset + 1;
write_bits(this->ch, this->bit_offset, 0, bits_to_write, this->pl); write_bits(this->ch, this->bit_offset, 0, bits_to_write, this->pl);
} }

View File

@ -7,21 +7,17 @@ Buffer::Members::Members(size_t size, unsigned char* buf, bool own_memory) :
size(size), size(size),
buf(0) buf(0)
{ {
if (own_memory) if (own_memory) {
{
this->buf = (size ? new unsigned char[size] : 0); this->buf = (size ? new unsigned char[size] : 0);
} } else {
else
{
this->buf = buf; this->buf = buf;
} }
} }
Buffer::Members::~Members() Buffer::Members::~Members()
{ {
if (this->own_memory) if (this->own_memory) {
{ delete[] this->buf;
delete [] this->buf;
} }
} }
@ -55,11 +51,9 @@ Buffer::operator=(Buffer const& rhs)
void void
Buffer::copy(Buffer const& rhs) Buffer::copy(Buffer const& rhs)
{ {
if (this != &rhs) if (this != &rhs) {
{
this->m = PointerHolder<Members>(new Members(rhs.m->size, 0, true)); this->m = PointerHolder<Members>(new Members(rhs.m->size, 0, true));
if (this->m->size) if (this->m->size) {
{
memcpy(this->m->buf, rhs.m->buf, this->m->size); memcpy(this->m->buf, rhs.m->buf, this->m->size);
} }
} }

View File

@ -1,15 +1,14 @@
#include <qpdf/BufferInputSource.hh> #include <qpdf/BufferInputSource.hh>
#include <qpdf/QIntC.hh> #include <qpdf/QIntC.hh>
#include <string.h>
#include <stdexcept>
#include <algorithm> #include <algorithm>
#include <limits> #include <limits>
#include <sstream> #include <sstream>
#include <stdexcept>
#include <string.h>
BufferInputSource::Members::Members(bool own_memory, BufferInputSource::Members::Members(
std::string const& description, bool own_memory, std::string const& description, Buffer* buf) :
Buffer* buf) :
own_memory(own_memory), own_memory(own_memory),
description(description), description(description),
buf(buf), buf(buf),
@ -22,14 +21,14 @@ BufferInputSource::Members::~Members()
{ {
} }
BufferInputSource::BufferInputSource(std::string const& description, BufferInputSource::BufferInputSource(
Buffer* buf, bool own_memory) : std::string const& description, Buffer* buf, bool own_memory) :
m(new Members(own_memory, description, buf)) m(new Members(own_memory, description, buf))
{ {
} }
BufferInputSource::BufferInputSource(std::string const& description, BufferInputSource::BufferInputSource(
std::string const& contents) : std::string const& description, std::string const& contents) :
m(new Members(true, description, 0)) m(new Members(true, description, 0))
{ {
this->m->buf = new Buffer(contents.length()); this->m->buf = new Buffer(contents.length());
@ -40,8 +39,7 @@ BufferInputSource::BufferInputSource(std::string const& description,
BufferInputSource::~BufferInputSource() BufferInputSource::~BufferInputSource()
{ {
if (this->m->own_memory) if (this->m->own_memory) {
{
delete this->m->buf; delete this->m->buf;
} }
} }
@ -49,13 +47,11 @@ BufferInputSource::~BufferInputSource()
qpdf_offset_t qpdf_offset_t
BufferInputSource::findAndSkipNextEOL() BufferInputSource::findAndSkipNextEOL()
{ {
if (this->m->cur_offset < 0) if (this->m->cur_offset < 0) {
{
throw std::logic_error("INTERNAL ERROR: BufferInputSource offset < 0"); throw std::logic_error("INTERNAL ERROR: BufferInputSource offset < 0");
} }
qpdf_offset_t end_pos = this->m->max_offset; qpdf_offset_t end_pos = this->m->max_offset;
if (this->m->cur_offset >= end_pos) if (this->m->cur_offset >= end_pos) {
{
this->last_offset = end_pos; this->last_offset = end_pos;
this->m->cur_offset = end_pos; this->m->cur_offset = end_pos;
return end_pos; return end_pos;
@ -66,24 +62,19 @@ BufferInputSource::findAndSkipNextEOL()
unsigned char const* end = buffer + end_pos; unsigned char const* end = buffer + end_pos;
unsigned char const* p = buffer + this->m->cur_offset; unsigned char const* p = buffer + this->m->cur_offset;
while ((p < end) && !((*p == '\r') || (*p == '\n'))) while ((p < end) && !((*p == '\r') || (*p == '\n'))) {
{
++p; ++p;
} }
if (p < end) if (p < end) {
{
result = p - buffer; result = p - buffer;
this->m->cur_offset = result + 1; this->m->cur_offset = result + 1;
++p; ++p;
while ((this->m->cur_offset < end_pos) && while ((this->m->cur_offset < end_pos) &&
((*p == '\r') || (*p == '\n'))) ((*p == '\r') || (*p == '\n'))) {
{
++p; ++p;
++this->m->cur_offset; ++this->m->cur_offset;
} }
} } else {
else
{
this->m->cur_offset = end_pos; this->m->cur_offset = end_pos;
result = end_pos; result = end_pos;
} }
@ -105,30 +96,28 @@ BufferInputSource::tell()
void void
BufferInputSource::seek(qpdf_offset_t offset, int whence) BufferInputSource::seek(qpdf_offset_t offset, int whence)
{ {
switch (whence) switch (whence) {
{ case SEEK_SET:
case SEEK_SET:
this->m->cur_offset = offset; this->m->cur_offset = offset;
break; break;
case SEEK_END: case SEEK_END:
QIntC::range_check(this->m->max_offset, offset); QIntC::range_check(this->m->max_offset, offset);
this->m->cur_offset = this->m->max_offset + offset; this->m->cur_offset = this->m->max_offset + offset;
break; break;
case SEEK_CUR: case SEEK_CUR:
QIntC::range_check(this->m->cur_offset, offset); QIntC::range_check(this->m->cur_offset, offset);
this->m->cur_offset += offset; this->m->cur_offset += offset;
break; break;
default: default:
throw std::logic_error( throw std::logic_error(
"INTERNAL ERROR: invalid argument to BufferInputSource::seek"); "INTERNAL ERROR: invalid argument to BufferInputSource::seek");
break; break;
} }
if (this->m->cur_offset < 0) if (this->m->cur_offset < 0) {
{
throw std::runtime_error( throw std::runtime_error(
this->m->description + ": seek before beginning of buffer"); this->m->description + ": seek before beginning of buffer");
} }
@ -143,20 +132,18 @@ BufferInputSource::rewind()
size_t size_t
BufferInputSource::read(char* buffer, size_t length) BufferInputSource::read(char* buffer, size_t length)
{ {
if (this->m->cur_offset < 0) if (this->m->cur_offset < 0) {
{
throw std::logic_error("INTERNAL ERROR: BufferInputSource offset < 0"); throw std::logic_error("INTERNAL ERROR: BufferInputSource offset < 0");
} }
qpdf_offset_t end_pos = this->m->max_offset; qpdf_offset_t end_pos = this->m->max_offset;
if (this->m->cur_offset >= end_pos) if (this->m->cur_offset >= end_pos) {
{
this->last_offset = end_pos; this->last_offset = end_pos;
return 0; return 0;
} }
this->last_offset = this->m->cur_offset; this->last_offset = this->m->cur_offset;
size_t len = std::min( size_t len =
QIntC::to_size(end_pos - this->m->cur_offset), length); std::min(QIntC::to_size(end_pos - this->m->cur_offset), length);
memcpy(buffer, this->m->buf->getBuffer() + this->m->cur_offset, len); memcpy(buffer, this->m->buf->getBuffer() + this->m->cur_offset, len);
this->m->cur_offset += QIntC::to_offset(len); this->m->cur_offset += QIntC::to_offset(len);
return len; return len;
@ -165,8 +152,7 @@ BufferInputSource::read(char* buffer, size_t length)
void void
BufferInputSource::unreadCh(char ch) BufferInputSource::unreadCh(char ch)
{ {
if (this->m->cur_offset > 0) if (this->m->cur_offset > 0) {
{
--this->m->cur_offset; --this->m->cur_offset;
} }
} }

View File

@ -25,8 +25,7 @@ ClosedFileInputSource::~ClosedFileInputSource()
void void
ClosedFileInputSource::before() ClosedFileInputSource::before()
{ {
if (0 == this->m->fis.get()) if (0 == this->m->fis.get()) {
{
this->m->fis = make_pointer_holder<FileInputSource>(); this->m->fis = make_pointer_holder<FileInputSource>();
this->m->fis->setFilename(this->m->filename.c_str()); this->m->fis->setFilename(this->m->filename.c_str());
this->m->fis->seek(this->m->offset, SEEK_SET); this->m->fis->seek(this->m->offset, SEEK_SET);
@ -39,8 +38,7 @@ ClosedFileInputSource::after()
{ {
this->last_offset = this->m->fis->getLastOffset(); this->last_offset = this->m->fis->getLastOffset();
this->m->offset = this->m->fis->tell(); this->m->offset = this->m->fis->tell();
if (this->m->stay_open) if (this->m->stay_open) {
{
return; return;
} }
this->m->fis = 0; this->m->fis = 0;
@ -82,8 +80,7 @@ void
ClosedFileInputSource::rewind() ClosedFileInputSource::rewind()
{ {
this->m->offset = 0; this->m->offset = 0;
if (this->m->fis.get()) if (this->m->fis.get()) {
{
this->m->fis->rewind(); this->m->fis->rewind();
} }
} }
@ -110,8 +107,7 @@ void
ClosedFileInputSource::stayOpen(bool val) ClosedFileInputSource::stayOpen(bool val)
{ {
this->m->stay_open = val; this->m->stay_open = val;
if ((! val) && this->m->fis.get()) if ((!val) && this->m->fis.get()) {
{
after(); after();
} }
} }

View File

@ -18,57 +18,46 @@ ContentNormalizer::handleToken(QPDFTokenizer::Token const& token)
std::string value = token.getRawValue(); std::string value = token.getRawValue();
QPDFTokenizer::token_type_e token_type = token.getType(); QPDFTokenizer::token_type_e token_type = token.getType();
if (token_type == QPDFTokenizer::tt_bad) if (token_type == QPDFTokenizer::tt_bad) {
{
this->any_bad_tokens = true; this->any_bad_tokens = true;
this->last_token_was_bad = true; this->last_token_was_bad = true;
} } else if (token_type != QPDFTokenizer::tt_eof) {
else if (token_type != QPDFTokenizer::tt_eof)
{
this->last_token_was_bad = false; this->last_token_was_bad = false;
} }
switch (token_type) switch (token_type) {
{ case QPDFTokenizer::tt_space:
case QPDFTokenizer::tt_space:
{ {
size_t len = value.length(); size_t len = value.length();
for (size_t i = 0; i < len; ++i) for (size_t i = 0; i < len; ++i) {
{
char ch = value.at(i); char ch = value.at(i);
if (ch == '\r') if (ch == '\r') {
{ if ((i + 1 < len) && (value.at(i + 1) == '\n')) {
if ((i + 1 < len) && (value.at(i + 1) == '\n'))
{
// ignore // ignore
} } else {
else
{
write("\n"); write("\n");
} }
} } else {
else
{
write(&ch, 1); write(&ch, 1);
} }
} }
} }
break; break;
case QPDFTokenizer::tt_string: case QPDFTokenizer::tt_string:
// Replacing string and name tokens in this way normalizes // Replacing string and name tokens in this way normalizes
// their representation as this will automatically handle // their representation as this will automatically handle
// quoting of unprintable characters, etc. // quoting of unprintable characters, etc.
writeToken(QPDFTokenizer::Token( writeToken(
QPDFTokenizer::tt_string, token.getValue())); QPDFTokenizer::Token(QPDFTokenizer::tt_string, token.getValue()));
break; break;
case QPDFTokenizer::tt_name: case QPDFTokenizer::tt_name:
writeToken(QPDFTokenizer::Token( writeToken(
QPDFTokenizer::tt_name, token.getValue())); QPDFTokenizer::Token(QPDFTokenizer::tt_name, token.getValue()));
break; break;
default: default:
writeToken(token); writeToken(token);
break; break;
} }
@ -77,8 +66,7 @@ ContentNormalizer::handleToken(QPDFTokenizer::Token const& token)
if (((token_type == QPDFTokenizer::tt_string) || if (((token_type == QPDFTokenizer::tt_string) ||
(token_type == QPDFTokenizer::tt_name)) && (token_type == QPDFTokenizer::tt_name)) &&
((value.find('\r') != std::string::npos) || ((value.find('\r') != std::string::npos) ||
(value.find('\n') != std::string::npos))) (value.find('\n') != std::string::npos))) {
{
write("\n"); write("\n");
} }
} }
@ -90,7 +78,7 @@ ContentNormalizer::anyBadTokens() const
} }
bool bool
ContentNormalizer::lastTokenWasBad()const ContentNormalizer::lastTokenWasBad() const
{ {
return this->last_token_was_bad; return this->last_token_was_bad;
} }

View File

@ -1,9 +1,9 @@
#include <qpdf/FileInputSource.hh> #include <qpdf/FileInputSource.hh>
#include <string.h>
#include <qpdf/QUtil.hh>
#include <qpdf/QPDFExc.hh> #include <qpdf/QPDFExc.hh>
#include <qpdf/QUtil.hh>
#include <algorithm> #include <algorithm>
#include <string.h>
FileInputSource::Members::Members(bool close_file) : FileInputSource::Members::Members(bool close_file) :
close_file(close_file), close_file(close_file),
@ -13,8 +13,7 @@ FileInputSource::Members::Members(bool close_file) :
FileInputSource::Members::~Members() FileInputSource::Members::~Members()
{ {
if (this->file && this->close_file) if (this->file && this->close_file) {
{
fclose(this->file); fclose(this->file);
} }
} }
@ -33,8 +32,7 @@ FileInputSource::setFilename(char const* filename)
} }
void void
FileInputSource::setFile( FileInputSource::setFile(char const* description, FILE* filep, bool close_file)
char const* description, FILE* filep, bool close_file)
{ {
this->m = PointerHolder<Members>(new Members(close_file)); this->m = PointerHolder<Members>(new Members(close_file));
this->m->filename = description; this->m->filename = description;
@ -52,35 +50,26 @@ FileInputSource::findAndSkipNextEOL()
qpdf_offset_t result = 0; qpdf_offset_t result = 0;
bool done = false; bool done = false;
char buf[10240]; char buf[10240];
while (! done) while (!done) {
{
qpdf_offset_t cur_offset = QUtil::tell(this->m->file); qpdf_offset_t cur_offset = QUtil::tell(this->m->file);
size_t len = this->read(buf, sizeof(buf)); size_t len = this->read(buf, sizeof(buf));
if (len == 0) if (len == 0) {
{
done = true; done = true;
result = this->tell(); result = this->tell();
} } else {
else
{
char* p1 = static_cast<char*>(memchr(buf, '\r', len)); char* p1 = static_cast<char*>(memchr(buf, '\r', len));
char* p2 = static_cast<char*>(memchr(buf, '\n', len)); char* p2 = static_cast<char*>(memchr(buf, '\n', len));
char* p = (p1 && p2) ? std::min(p1, p2) : p1 ? p1 : p2; char* p = (p1 && p2) ? std::min(p1, p2) : p1 ? p1 : p2;
if (p) if (p) {
{
result = cur_offset + (p - buf); result = cur_offset + (p - buf);
// We found \r or \n. Keep reading until we get past // We found \r or \n. Keep reading until we get past
// \r and \n characters. // \r and \n characters.
this->seek(result + 1, SEEK_SET); this->seek(result + 1, SEEK_SET);
char ch; char ch;
while (! done) while (!done) {
{ if (this->read(&ch, 1) == 0) {
if (this->read(&ch, 1) == 0)
{
done = true; done = true;
} } else if (!((ch == '\r') || (ch == '\n'))) {
else if (! ((ch == '\r') || (ch == '\n')))
{
this->unreadCh(ch); this->unreadCh(ch);
done = true; done = true;
} }
@ -106,11 +95,11 @@ FileInputSource::tell()
void void
FileInputSource::seek(qpdf_offset_t offset, int whence) FileInputSource::seek(qpdf_offset_t offset, int whence)
{ {
QUtil::os_wrapper(std::string("seek to ") + QUtil::os_wrapper(
this->m->filename + ", offset " + std::string("seek to ") + this->m->filename + ", offset " +
QUtil::int_to_string(offset) + " (" + QUtil::int_to_string(offset) + " (" + QUtil::int_to_string(whence) +
QUtil::int_to_string(whence) + ")", ")",
QUtil::seek(this->m->file, offset, whence)); QUtil::seek(this->m->file, offset, whence));
} }
void void
@ -124,18 +113,16 @@ FileInputSource::read(char* buffer, size_t length)
{ {
this->last_offset = this->tell(); this->last_offset = this->tell();
size_t len = fread(buffer, 1, length, this->m->file); size_t len = fread(buffer, 1, length, this->m->file);
if (len == 0) if (len == 0) {
{ if (ferror(this->m->file)) {
if (ferror(this->m->file)) throw QPDFExc(
{ qpdf_e_system,
throw QPDFExc(qpdf_e_system, this->m->filename,
this->m->filename, "", "",
this->last_offset, this->last_offset,
std::string("read ") + std::string("read ") + QUtil::uint_to_string(length) +
QUtil::uint_to_string(length) + " bytes"); " bytes");
} } else if (length > 0) {
else if (length > 0)
{
this->seek(0, SEEK_END); this->seek(0, SEEK_END);
this->last_offset = this->tell(); this->last_offset = this->tell();
} }
@ -146,6 +133,7 @@ FileInputSource::read(char* buffer, size_t length)
void void
FileInputSource::unreadCh(char ch) FileInputSource::unreadCh(char ch)
{ {
QUtil::os_wrapper(this->m->filename + ": unread character", QUtil::os_wrapper(
ungetc(static_cast<unsigned char>(ch), this->m->file)); this->m->filename + ": unread character",
ungetc(static_cast<unsigned char>(ch), this->m->file));
} }

View File

@ -1,10 +1,10 @@
#include <qpdf/InputSource.hh> #include <qpdf/InputSource.hh>
#include <string.h>
#include <stdexcept>
#include <qpdf/QTC.hh>
#include <qpdf/PointerHolder.hh> #include <qpdf/PointerHolder.hh>
#include <qpdf/QIntC.hh> #include <qpdf/QIntC.hh>
#include <qpdf/QTC.hh>
#include <stdexcept>
#include <string.h>
InputSource::Members::Members() InputSource::Members::Members()
{ {
@ -45,17 +45,15 @@ InputSource::readLine(size_t max_line_length)
qpdf_offset_t eol = this->findAndSkipNextEOL(); qpdf_offset_t eol = this->findAndSkipNextEOL();
this->last_offset = offset; this->last_offset = offset;
size_t line_length = QIntC::to_size(eol - offset); size_t line_length = QIntC::to_size(eol - offset);
if (line_length < max_line_length) if (line_length < max_line_length) {
{
buf[line_length] = '\0'; buf[line_length] = '\0';
} }
return std::string(buf); return std::string(buf);
} }
bool bool
InputSource::findFirst(char const* start_chars, InputSource::findFirst(
qpdf_offset_t offset, size_t len, char const* start_chars, qpdf_offset_t offset, size_t len, Finder& finder)
Finder& finder)
{ {
// Basic approach: search for the first character of start_chars // Basic approach: search for the first character of start_chars
// starting from offset but not going past len (if len != 0). Once // starting from offset but not going past len (if len != 0). Once
@ -74,8 +72,7 @@ InputSource::findFirst(char const* start_chars,
// To enable us to guarantee null-termination, save an extra byte // To enable us to guarantee null-termination, save an extra byte
// so that buf[size] is valid memory. // so that buf[size] is valid memory.
size_t size = sizeof(buf) - 1; size_t size = sizeof(buf) - 1;
if ((strlen(start_chars) < 1) || (strlen(start_chars) > size)) if ((strlen(start_chars) < 1) || (strlen(start_chars) > size)) {
{
throw std::logic_error( throw std::logic_error(
"InputSource::findSource called with" "InputSource::findSource called with"
" too small or too large of a character sequence"); " too small or too large of a character sequence");
@ -90,8 +87,7 @@ InputSource::findFirst(char const* start_chars,
// that will cause return on the next pass. Eventually we will // that will cause return on the next pass. Eventually we will
// either be out of range or hit EOF, either of which forces us to // either be out of range or hit EOF, either of which forces us to
// return. // return.
while (true) while (true) {
{
// Do we need to read more data? Pretend size = 5, buf starts // Do we need to read more data? Pretend size = 5, buf starts
// at 0, and start_chars has 3 characters. buf[5] is valid and // at 0, and start_chars has 3 characters. buf[5] is valid and
// null. If p == 2, start_chars could be buf[2] through // null. If p == 2, start_chars could be buf[2] through
@ -99,12 +95,12 @@ InputSource::findFirst(char const* start_chars,
// If p points to buf[size], since strlen(start_chars) is // If p points to buf[size], since strlen(start_chars) is
// always >= 1, this overflow test will be correct for that // always >= 1, this overflow test will be correct for that
// case regardless of start_chars. // case regardless of start_chars.
if ((p == 0) || ((p + strlen(start_chars)) > (buf + bytes_read))) if ((p == 0) || ((p + strlen(start_chars)) > (buf + bytes_read))) {
{ if (p) {
if (p) QTC::TC(
{ "libtests",
QTC::TC("libtests", "InputSource read next block", "InputSource read next block",
((p == buf + bytes_read) ? 0 : 1)); ((p == buf + bytes_read) ? 0 : 1));
buf_offset += (p - buf); buf_offset += (p - buf);
} }
this->seek(buf_offset, SEEK_SET); this->seek(buf_offset, SEEK_SET);
@ -113,10 +109,11 @@ InputSource::findFirst(char const* start_chars,
// we could guarantee null termination as an extra // we could guarantee null termination as an extra
// protection against overrun when using string functions. // protection against overrun when using string functions.
bytes_read = this->read(buf, size); bytes_read = this->read(buf, size);
if (bytes_read < strlen(start_chars)) if (bytes_read < strlen(start_chars)) {
{ QTC::TC(
QTC::TC("libtests", "InputSource find EOF", "libtests",
bytes_read == 0 ? 0 : 1); "InputSource find EOF",
bytes_read == 0 ? 0 : 1);
return false; return false;
} }
memset(buf + bytes_read, '\0', 1 + (size - bytes_read)); memset(buf + bytes_read, '\0', 1 + (size - bytes_read));
@ -124,29 +121,24 @@ InputSource::findFirst(char const* start_chars,
} }
// Search for the first character. // Search for the first character.
if ((p = static_cast<char*>( if ((p = static_cast<char*>(memchr(
memchr(p, start_chars[0], p, start_chars[0], bytes_read - QIntC::to_size(p - buf)))) !=
bytes_read - QIntC::to_size(p - buf)))) != 0) 0) {
{ if (p == buf) {
if (p == buf)
{
QTC::TC("libtests", "InputSource found match at buf[0]"); QTC::TC("libtests", "InputSource found match at buf[0]");
} }
// Found first letter. // Found first letter.
if (len != 0) if (len != 0) {
{
// Make sure it's in range. // Make sure it's in range.
size_t p_relative_offset = size_t p_relative_offset =
QIntC::to_size((p - buf) + (buf_offset - offset)); QIntC::to_size((p - buf) + (buf_offset - offset));
if (p_relative_offset >= len) if (p_relative_offset >= len) {
{
// out of range // out of range
QTC::TC("libtests", "InputSource out of range"); QTC::TC("libtests", "InputSource out of range");
return false; return false;
} }
} }
if ((p + strlen(start_chars)) > (buf + bytes_read)) if ((p + strlen(start_chars)) > (buf + bytes_read)) {
{
// If there are not enough bytes left in the file for // If there are not enough bytes left in the file for
// start_chars, we will detect this on the next pass // start_chars, we will detect this on the next pass
// as EOF and return. // as EOF and return.
@ -157,30 +149,26 @@ InputSource::findFirst(char const* start_chars,
// See if p points to a sequence matching start_chars. We // See if p points to a sequence matching start_chars. We
// already checked above to make sure we are not going to // already checked above to make sure we are not going to
// overrun memory. // overrun memory.
if (strncmp(p, start_chars, strlen(start_chars)) == 0) if (strncmp(p, start_chars, strlen(start_chars)) == 0) {
{
// Call finder.check() with the input source // Call finder.check() with the input source
// positioned to the point of the match. // positioned to the point of the match.
this->seek(buf_offset + (p - buf), SEEK_SET); this->seek(buf_offset + (p - buf), SEEK_SET);
if (finder.check()) if (finder.check()) {
{
return true; return true;
} else {
QTC::TC(
"libtests",
"InputSource start_chars matched but not check");
} }
else } else {
{ QTC::TC(
QTC::TC("libtests", "InputSource start_chars matched but not check"); "libtests",
} "InputSource first char matched but not string");
}
else
{
QTC::TC("libtests", "InputSource first char matched but not string");
} }
// This occurrence of the first character wasn't a match. // This occurrence of the first character wasn't a match.
// Skip over it and keep searching. // Skip over it and keep searching.
++p; ++p;
} } else {
else
{
// Trigger reading the next block // Trigger reading the next block
p = buf + bytes_read; p = buf + bytes_read;
} }
@ -189,30 +177,24 @@ InputSource::findFirst(char const* start_chars,
} }
bool bool
InputSource::findLast(char const* start_chars, InputSource::findLast(
qpdf_offset_t offset, size_t len, char const* start_chars, qpdf_offset_t offset, size_t len, Finder& finder)
Finder& finder)
{ {
bool found = false; bool found = false;
qpdf_offset_t after_found_offset = 0; qpdf_offset_t after_found_offset = 0;
qpdf_offset_t cur_offset = offset; qpdf_offset_t cur_offset = offset;
size_t cur_len = len; size_t cur_len = len;
while (this->findFirst(start_chars, cur_offset, cur_len, finder)) while (this->findFirst(start_chars, cur_offset, cur_len, finder)) {
{ if (found) {
if (found)
{
QTC::TC("libtests", "InputSource findLast found more than one"); QTC::TC("libtests", "InputSource findLast found more than one");
} } else {
else
{
found = true; found = true;
} }
after_found_offset = this->tell(); after_found_offset = this->tell();
cur_offset = after_found_offset; cur_offset = after_found_offset;
cur_len = len - QIntC::to_size((cur_offset - offset)); cur_len = len - QIntC::to_size((cur_offset - offset));
} }
if (found) if (found) {
{
this->seek(after_found_offset, SEEK_SET); this->seek(after_found_offset, SEEK_SET);
} }
return found; return found;

View File

@ -1,7 +1,7 @@
#include <qpdf/InsecureRandomDataProvider.hh> #include <qpdf/InsecureRandomDataProvider.hh>
#include <qpdf/qpdf-config.h>
#include <qpdf/QUtil.hh> #include <qpdf/QUtil.hh>
#include <qpdf/qpdf-config.h>
#include <stdlib.h> #include <stdlib.h>
InsecureRandomDataProvider::InsecureRandomDataProvider() : InsecureRandomDataProvider::InsecureRandomDataProvider() :
@ -16,8 +16,7 @@ InsecureRandomDataProvider::~InsecureRandomDataProvider()
void void
InsecureRandomDataProvider::provideRandomData(unsigned char* data, size_t len) InsecureRandomDataProvider::provideRandomData(unsigned char* data, size_t len)
{ {
for (size_t i = 0; i < len; ++i) for (size_t i = 0; i < len; ++i) {
{
data[i] = static_cast<unsigned char>((this->random() & 0xff0) >> 4); data[i] = static_cast<unsigned char>((this->random() & 0xff0) >> 4);
} }
} }
@ -25,13 +24,12 @@ InsecureRandomDataProvider::provideRandomData(unsigned char* data, size_t len)
long long
InsecureRandomDataProvider::random() InsecureRandomDataProvider::random()
{ {
if (! this->seeded_random) if (!this->seeded_random) {
{
// Seed the random number generator with something simple, but // Seed the random number generator with something simple, but
// just to be interesting, don't use the unmodified current // just to be interesting, don't use the unmodified current
// time. It would be better if this were a more secure seed. // time. It would be better if this were a more secure seed.
unsigned int seed = static_cast<unsigned int>( unsigned int seed =
QUtil::get_current_time() ^ 0xcccc); static_cast<unsigned int>(QUtil::get_current_time() ^ 0xcccc);
#ifdef HAVE_RANDOM #ifdef HAVE_RANDOM
::srandom(seed); ::srandom(seed);
#else #else
@ -40,11 +38,11 @@ InsecureRandomDataProvider::random()
this->seeded_random = true; this->seeded_random = true;
} }
# ifdef HAVE_RANDOM #ifdef HAVE_RANDOM
return ::random(); return ::random();
# else #else
return rand(); return rand();
# endif #endif
} }
RandomDataProvider* RandomDataProvider*

File diff suppressed because it is too large Load Diff

View File

@ -1,8 +1,8 @@
#include <qpdf/JSONHandler.hh> #include <qpdf/JSONHandler.hh>
#include <qpdf/QUtil.hh>
#include <qpdf/QTC.hh>
#include <qpdf/QPDFUsage.hh> #include <qpdf/QPDFUsage.hh>
#include <qpdf/QTC.hh>
#include <qpdf/QUtil.hh>
JSONHandler::JSONHandler() : JSONHandler::JSONHandler() :
m(new Members()) m(new Members())
@ -70,9 +70,10 @@ JSONHandler::addFallbackDictHandler(std::shared_ptr<JSONHandler> fdh)
} }
void void
JSONHandler::addArrayHandlers(json_handler_t start_fn, JSONHandler::addArrayHandlers(
void_handler_t end_fn, json_handler_t start_fn,
std::shared_ptr<JSONHandler> ah) void_handler_t end_fn,
std::shared_ptr<JSONHandler> ah)
{ {
this->m->h.array_start_handler = start_fn; this->m->h.array_start_handler = start_fn;
this->m->h.array_end_handler = end_fn; this->m->h.array_end_handler = end_fn;
@ -82,69 +83,55 @@ JSONHandler::addArrayHandlers(json_handler_t start_fn,
void void
JSONHandler::handle(std::string const& path, JSON j) JSONHandler::handle(std::string const& path, JSON j)
{ {
if (this->m->h.any_handler) if (this->m->h.any_handler) {
{
this->m->h.any_handler(path, j); this->m->h.any_handler(path, j);
return; return;
} }
bool handled = false; bool handled = false;
bool bvalue = false; bool bvalue = false;
std::string s_value; std::string s_value;
if (this->m->h.null_handler && j.isNull()) if (this->m->h.null_handler && j.isNull()) {
{
this->m->h.null_handler(path); this->m->h.null_handler(path);
handled = true; handled = true;
} }
if (this->m->h.string_handler && j.getString(s_value)) if (this->m->h.string_handler && j.getString(s_value)) {
{
this->m->h.string_handler(path, s_value); this->m->h.string_handler(path, s_value);
handled = true; handled = true;
} }
if (this->m->h.number_handler && j.getNumber(s_value)) if (this->m->h.number_handler && j.getNumber(s_value)) {
{
this->m->h.number_handler(path, s_value); this->m->h.number_handler(path, s_value);
handled = true; handled = true;
} }
if (this->m->h.bool_handler && j.getBool(bvalue)) if (this->m->h.bool_handler && j.getBool(bvalue)) {
{
this->m->h.bool_handler(path, bvalue); this->m->h.bool_handler(path, bvalue);
handled = true; handled = true;
} }
if (this->m->h.dict_start_handler && j.isDictionary()) if (this->m->h.dict_start_handler && j.isDictionary()) {
{
this->m->h.dict_start_handler(path, j); this->m->h.dict_start_handler(path, j);
std::string path_base = path; std::string path_base = path;
if (path_base != ".") if (path_base != ".") {
{
path_base += "."; path_base += ".";
} }
j.forEachDictItem([&path, &path_base, this]( j.forEachDictItem([&path, &path_base, this](
std::string const& k, JSON v) { std::string const& k, JSON v) {
auto i = this->m->h.dict_handlers.find(k); auto i = this->m->h.dict_handlers.find(k);
if (i == this->m->h.dict_handlers.end()) if (i == this->m->h.dict_handlers.end()) {
{ if (this->m->h.fallback_dict_handler.get()) {
if (this->m->h.fallback_dict_handler.get()) this->m->h.fallback_dict_handler->handle(path_base + k, v);
{ } else {
this->m->h.fallback_dict_handler->handle(
path_base + k, v);
}
else
{
QTC::TC("libtests", "JSONHandler unexpected key"); QTC::TC("libtests", "JSONHandler unexpected key");
usage("JSON handler found unexpected key " + k + usage(
" in object at " + path); "JSON handler found unexpected key " + k +
" in object at " + path);
} }
} } else {
else
{
i->second->handle(path_base + k, v); i->second->handle(path_base + k, v);
} }
}); });
this->m->h.dict_end_handler(path); this->m->h.dict_end_handler(path);
handled = true; handled = true;
} }
if (this->m->h.array_start_handler && j.isArray()) if (this->m->h.array_start_handler && j.isArray()) {
{
this->m->h.array_start_handler(path, j); this->m->h.array_start_handler(path, j);
size_t i = 0; size_t i = 0;
j.forEachArrayItem([&i, &path, this](JSON v) { j.forEachArrayItem([&i, &path, this](JSON v) {
@ -156,8 +143,7 @@ JSONHandler::handle(std::string const& path, JSON j)
handled = true; handled = true;
} }
if (! handled) if (!handled) {
{
// It would be nice to include information about what type the // It would be nice to include information about what type the
// object was and what types were allowed, but we're relying // object was and what types were allowed, but we're relying
// on schema validation to make sure input is properly // on schema validation to make sure input is properly

View File

@ -1,14 +1,14 @@
#include <qpdf/MD5.hh> #include <qpdf/MD5.hh>
#include <qpdf/QUtil.hh>
#include <qpdf/QIntC.hh> #include <qpdf/QIntC.hh>
#include <qpdf/QPDFCryptoProvider.hh> #include <qpdf/QPDFCryptoProvider.hh>
#include <qpdf/QUtil.hh>
#include <stdio.h> #include <errno.h>
#include <memory.h> #include <memory.h>
#include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <errno.h>
MD5::MD5() MD5::MD5()
{ {
@ -28,12 +28,14 @@ MD5::finalize()
this->crypto->MD5_finalize(); this->crypto->MD5_finalize();
} }
void MD5::reset() void
MD5::reset()
{ {
init(); init();
} }
void MD5::encodeString(char const* str) void
MD5::encodeString(char const* str)
{ {
size_t len = strlen(str); size_t len = strlen(str);
crypto->MD5_init(); crypto->MD5_init();
@ -41,79 +43,78 @@ void MD5::encodeString(char const* str)
crypto->MD5_finalize(); crypto->MD5_finalize();
} }
void MD5::appendString(char const* input_string) void
MD5::appendString(char const* input_string)
{ {
encodeDataIncrementally(input_string, strlen(input_string)); encodeDataIncrementally(input_string, strlen(input_string));
} }
void MD5::encodeDataIncrementally(char const* data, size_t len) void
MD5::encodeDataIncrementally(char const* data, size_t len)
{ {
this->crypto->MD5_update(QUtil::unsigned_char_pointer(data), len); this->crypto->MD5_update(QUtil::unsigned_char_pointer(data), len);
} }
void MD5::encodeFile(char const *filename, qpdf_offset_t up_to_offset) void
MD5::encodeFile(char const* filename, qpdf_offset_t up_to_offset)
{ {
char buffer[1024]; char buffer[1024];
FILE *file = QUtil::safe_fopen(filename, "rb"); FILE* file = QUtil::safe_fopen(filename, "rb");
size_t len; size_t len;
size_t so_far = 0; size_t so_far = 0;
size_t to_try = 1024; size_t to_try = 1024;
size_t up_to_size = 0; size_t up_to_size = 0;
if (up_to_offset >= 0) if (up_to_offset >= 0) {
{
up_to_size = QIntC::to_size(up_to_offset); up_to_size = QIntC::to_size(up_to_offset);
} }
do do {
{ if ((up_to_offset >= 0) && ((so_far + to_try) > up_to_size)) {
if ((up_to_offset >= 0) && ((so_far + to_try) > up_to_size))
{
to_try = up_to_size - so_far; to_try = up_to_size - so_far;
} }
len = fread(buffer, 1, to_try, file); len = fread(buffer, 1, to_try, file);
if (len > 0) if (len > 0) {
{
encodeDataIncrementally(buffer, len); encodeDataIncrementally(buffer, len);
so_far += len; so_far += len;
if ((up_to_offset >= 0) && (so_far >= up_to_size)) if ((up_to_offset >= 0) && (so_far >= up_to_size)) {
{
break; break;
} }
} }
} while (len > 0); } while (len > 0);
if (ferror(file)) if (ferror(file)) {
{
// Assume, perhaps incorrectly, that errno was set by the // Assume, perhaps incorrectly, that errno was set by the
// underlying call to read.... // underlying call to read....
(void) fclose(file); (void)fclose(file);
QUtil::throw_system_error( QUtil::throw_system_error(
std::string("MD5: read error on ") + filename); std::string("MD5: read error on ") + filename);
} }
(void) fclose(file); (void)fclose(file);
this->crypto->MD5_finalize(); this->crypto->MD5_finalize();
} }
void MD5::digest(Digest result) void
MD5::digest(Digest result)
{ {
this->crypto->MD5_finalize(); this->crypto->MD5_finalize();
this->crypto->MD5_digest(result); this->crypto->MD5_digest(result);
} }
void MD5::print() void
MD5::print()
{ {
Digest digest_val; Digest digest_val;
digest(digest_val); digest(digest_val);
unsigned int i; unsigned int i;
for (i = 0; i < 16; ++i) for (i = 0; i < 16; ++i) {
{
printf("%02x", digest_val[i]); printf("%02x", digest_val[i]);
} }
printf("\n"); printf("\n");
} }
std::string MD5::unparse() std::string
MD5::unparse()
{ {
this->crypto->MD5_finalize(); this->crypto->MD5_finalize();
Digest digest_val; Digest digest_val;
@ -139,25 +140,23 @@ MD5::getFileChecksum(char const* filename, qpdf_offset_t up_to_offset)
} }
bool bool
MD5::checkDataChecksum(char const* const checksum, MD5::checkDataChecksum(char const* const checksum, char const* buf, size_t len)
char const* buf, size_t len)
{ {
std::string actual_checksum = getDataChecksum(buf, len); std::string actual_checksum = getDataChecksum(buf, len);
return (checksum == actual_checksum); return (checksum == actual_checksum);
} }
bool bool
MD5::checkFileChecksum(char const* const checksum, MD5::checkFileChecksum(
char const* filename, qpdf_offset_t up_to_offset) char const* const checksum,
char const* filename,
qpdf_offset_t up_to_offset)
{ {
bool result = false; bool result = false;
try try {
{
std::string actual_checksum = getFileChecksum(filename, up_to_offset); std::string actual_checksum = getFileChecksum(filename, up_to_offset);
result = (checksum == actual_checksum); result = (checksum == actual_checksum);
} } catch (std::runtime_error const&) {
catch (std::runtime_error const&)
{
// Ignore -- return false // Ignore -- return false
} }
return result; return result;

File diff suppressed because it is too large Load Diff

View File

@ -4,13 +4,12 @@
#include <sstream> #include <sstream>
#include <stdexcept> #include <stdexcept>
OffsetInputSource::OffsetInputSource(PointerHolder<InputSource> proxied, OffsetInputSource::OffsetInputSource(
qpdf_offset_t global_offset) : PointerHolder<InputSource> proxied, qpdf_offset_t global_offset) :
proxied(proxied), proxied(proxied),
global_offset(global_offset) global_offset(global_offset)
{ {
if (global_offset < 0) if (global_offset < 0) {
{
throw std::logic_error( throw std::logic_error(
"OffsetInputSource constructed with negative offset"); "OffsetInputSource constructed with negative offset");
} }
@ -43,25 +42,19 @@ OffsetInputSource::tell()
void void
OffsetInputSource::seek(qpdf_offset_t offset, int whence) OffsetInputSource::seek(qpdf_offset_t offset, int whence)
{ {
if (whence == SEEK_SET) if (whence == SEEK_SET) {
{ if (offset > this->max_safe_offset) {
if (offset > this->max_safe_offset)
{
std::ostringstream msg; std::ostringstream msg;
msg.imbue(std::locale::classic()); msg.imbue(std::locale::classic());
msg << "seeking to " << offset msg << "seeking to " << offset << " offset by " << global_offset
<< " offset by " << global_offset
<< " would cause an overflow of the offset type"; << " would cause an overflow of the offset type";
throw std::range_error(msg.str()); throw std::range_error(msg.str());
} }
this->proxied->seek(offset + global_offset, whence); this->proxied->seek(offset + global_offset, whence);
} } else {
else
{
this->proxied->seek(offset, whence); this->proxied->seek(offset, whence);
} }
if (tell() < 0) if (tell() < 0) {
{
throw std::runtime_error( throw std::runtime_error(
"offset input source: seek before beginning of file"); "offset input source: seek before beginning of file");
} }

View File

@ -7,7 +7,8 @@ PDFVersion::PDFVersion() :
{ {
} }
PDFVersion::PDFVersion(int major_version, int minor_version, int extension_level) : PDFVersion::PDFVersion(
int major_version, int minor_version, int extension_level) :
major_version(major_version), major_version(major_version),
minor_version(minor_version), minor_version(minor_version),
extension_level(extension_level) extension_level(extension_level)
@ -17,27 +18,28 @@ PDFVersion::PDFVersion(int major_version, int minor_version, int extension_level
bool bool
PDFVersion::operator<(PDFVersion const& rhs) const PDFVersion::operator<(PDFVersion const& rhs) const
{ {
return ((this->major_version < rhs.major_version) ? true : return (
(this->major_version > rhs.major_version) ? false : (this->major_version < rhs.major_version) ? true
(this->minor_version < rhs.minor_version) ? true : : (this->major_version > rhs.major_version) ? false
(this->minor_version > rhs.minor_version) ? false : : (this->minor_version < rhs.minor_version) ? true
(this->extension_level < rhs.extension_level) ? true : : (this->minor_version > rhs.minor_version) ? false
false); : (this->extension_level < rhs.extension_level) ? true
: false);
} }
bool bool
PDFVersion::operator==(PDFVersion const& rhs) const PDFVersion::operator==(PDFVersion const& rhs) const
{ {
return ((this->major_version == rhs.major_version) && return (
(this->minor_version == rhs.minor_version) && (this->major_version == rhs.major_version) &&
(this->extension_level == rhs.extension_level)); (this->minor_version == rhs.minor_version) &&
(this->extension_level == rhs.extension_level));
} }
void void
PDFVersion::updateIfGreater(PDFVersion const& other) PDFVersion::updateIfGreater(PDFVersion const& other)
{ {
if (*this < other) if (*this < other) {
{
*this = other; *this = other;
} }
} }

View File

@ -15,8 +15,7 @@ Pipeline::~Pipeline()
Pipeline* Pipeline*
Pipeline::getNext(bool allow_null) Pipeline::getNext(bool allow_null)
{ {
if ((this->next == 0) && (! allow_null)) if ((this->next == 0) && (!allow_null)) {
{
throw std::logic_error( throw std::logic_error(
this->identifier + this->identifier +
": Pipeline::getNext() called on pipeline with no next"); ": Pipeline::getNext() called on pipeline with no next");

View File

@ -1,19 +1,22 @@
#include <qpdf/Pl_AES_PDF.hh> #include <qpdf/Pl_AES_PDF.hh>
#include <qpdf/QUtil.hh>
#include <cstring>
#include <assert.h>
#include <stdexcept>
#include <qpdf/QIntC.hh> #include <qpdf/QIntC.hh>
#include <qpdf/QPDFCryptoProvider.hh> #include <qpdf/QPDFCryptoProvider.hh>
#include <string> #include <qpdf/QUtil.hh>
#include <assert.h>
#include <cstring>
#include <stdexcept>
#include <stdlib.h> #include <stdlib.h>
#include <string>
bool Pl_AES_PDF::use_static_iv = false; bool Pl_AES_PDF::use_static_iv = false;
Pl_AES_PDF::Pl_AES_PDF(char const* identifier, Pipeline* next, Pl_AES_PDF::Pl_AES_PDF(
bool encrypt, unsigned char const* key, char const* identifier,
size_t key_bytes) : Pipeline* next,
bool encrypt,
unsigned char const* key,
size_t key_bytes) :
Pipeline(identifier, next), Pipeline(identifier, next),
crypto(QPDFCryptoProvider::getImpl()), crypto(QPDFCryptoProvider::getImpl()),
encrypt(encrypt), encrypt(encrypt),
@ -51,11 +54,11 @@ Pl_AES_PDF::disablePadding()
void void
Pl_AES_PDF::setIV(unsigned char const* iv, size_t bytes) Pl_AES_PDF::setIV(unsigned char const* iv, size_t bytes)
{ {
if (bytes != this->buf_size) if (bytes != this->buf_size) {
{
throw std::logic_error( throw std::logic_error(
"Pl_AES_PDF: specified initialization vector" "Pl_AES_PDF: specified initialization vector"
" size in bytes must be " + QUtil::uint_to_string(bytes)); " size in bytes must be " +
QUtil::uint_to_string(bytes));
} }
this->use_specified_iv = true; this->use_specified_iv = true;
memcpy(this->specified_iv, iv, bytes); memcpy(this->specified_iv, iv, bytes);
@ -79,10 +82,8 @@ Pl_AES_PDF::write(unsigned char* data, size_t len)
size_t bytes_left = len; size_t bytes_left = len;
unsigned char* p = data; unsigned char* p = data;
while (bytes_left > 0) while (bytes_left > 0) {
{ if (this->offset == this->buf_size) {
if (this->offset == this->buf_size)
{
flush(false); flush(false);
} }
@ -98,39 +99,32 @@ Pl_AES_PDF::write(unsigned char* data, size_t len)
void void
Pl_AES_PDF::finish() Pl_AES_PDF::finish()
{ {
if (this->encrypt) if (this->encrypt) {
{ if (this->offset == this->buf_size) {
if (this->offset == this->buf_size)
{
flush(false); flush(false);
} }
if (! this->disable_padding) if (!this->disable_padding) {
{
// Pad as described in section 3.5.1 of version 1.7 of the PDF // Pad as described in section 3.5.1 of version 1.7 of the PDF
// specification, including providing an entire block of padding // specification, including providing an entire block of padding
// if the input was a multiple of 16 bytes. // if the input was a multiple of 16 bytes.
unsigned char pad = unsigned char pad = QIntC::to_uchar(this->buf_size - this->offset);
QIntC::to_uchar(this->buf_size - this->offset);
memset(this->inbuf + this->offset, pad, pad); memset(this->inbuf + this->offset, pad, pad);
this->offset = this->buf_size; this->offset = this->buf_size;
flush(false); flush(false);
} }
} } else {
else if (this->offset != this->buf_size) {
{
if (this->offset != this->buf_size)
{
// This is never supposed to happen as the output is // This is never supposed to happen as the output is
// always supposed to be padded. However, we have // always supposed to be padded. However, we have
// encountered files for which the output is not a // encountered files for which the output is not a
// multiple of the block size. In this case, pad with // multiple of the block size. In this case, pad with
// zeroes and hope for the best. // zeroes and hope for the best.
assert(this->buf_size > this->offset); assert(this->buf_size > this->offset);
std::memset(this->inbuf + this->offset, 0, std::memset(
this->buf_size - this->offset); this->inbuf + this->offset, 0, this->buf_size - this->offset);
this->offset = this->buf_size; this->offset = this->buf_size;
} }
flush(! this->disable_padding); flush(!this->disable_padding);
} }
this->crypto->rijndael_finalize(); this->crypto->rijndael_finalize();
getNext()->finish(); getNext()->finish();
@ -139,26 +133,17 @@ Pl_AES_PDF::finish()
void void
Pl_AES_PDF::initializeVector() Pl_AES_PDF::initializeVector()
{ {
if (use_zero_iv) if (use_zero_iv) {
{ for (unsigned int i = 0; i < this->buf_size; ++i) {
for (unsigned int i = 0; i < this->buf_size; ++i)
{
this->cbc_block[i] = 0; this->cbc_block[i] = 0;
} }
} } else if (use_specified_iv) {
else if (use_specified_iv)
{
std::memcpy(this->cbc_block, this->specified_iv, this->buf_size); std::memcpy(this->cbc_block, this->specified_iv, this->buf_size);
} } else if (use_static_iv) {
else if (use_static_iv) for (unsigned int i = 0; i < this->buf_size; ++i) {
{
for (unsigned int i = 0; i < this->buf_size; ++i)
{
this->cbc_block[i] = static_cast<unsigned char>(14U * (1U + i)); this->cbc_block[i] = static_cast<unsigned char>(14U * (1U + i));
} }
} } else {
else
{
QUtil::initializeWithRandomBytes(this->cbc_block, this->buf_size); QUtil::initializeWithRandomBytes(this->cbc_block, this->buf_size);
} }
} }
@ -168,30 +153,22 @@ Pl_AES_PDF::flush(bool strip_padding)
{ {
assert(this->offset == this->buf_size); assert(this->offset == this->buf_size);
if (first) if (first) {
{
first = false; first = false;
bool return_after_init = false; bool return_after_init = false;
if (this->cbc_mode) if (this->cbc_mode) {
{ if (encrypt) {
if (encrypt)
{
// Set cbc_block to the initialization vector, and if // Set cbc_block to the initialization vector, and if
// not zero, write it to the output stream. // not zero, write it to the output stream.
initializeVector(); initializeVector();
if (! (this->use_zero_iv || this->use_specified_iv)) if (!(this->use_zero_iv || this->use_specified_iv)) {
{
getNext()->write(this->cbc_block, this->buf_size); getNext()->write(this->cbc_block, this->buf_size);
} }
} } else if (this->use_zero_iv || this->use_specified_iv) {
else if (this->use_zero_iv || this->use_specified_iv)
{
// Initialize vector with zeroes; zero vector was not // Initialize vector with zeroes; zero vector was not
// written to the beginning of the input file. // written to the beginning of the input file.
initializeVector(); initializeVector();
} } else {
else
{
// Take the first block of input as the initialization // Take the first block of input as the initialization
// vector. There's nothing to write at this time. // vector. There's nothing to write at this time.
memcpy(this->cbc_block, this->inbuf, this->buf_size); memcpy(this->cbc_block, this->inbuf, this->buf_size);
@ -200,32 +177,29 @@ Pl_AES_PDF::flush(bool strip_padding)
} }
} }
this->crypto->rijndael_init( this->crypto->rijndael_init(
encrypt, this->key.get(), key_bytes, encrypt,
this->cbc_mode, this->cbc_block); this->key.get(),
if (return_after_init) key_bytes,
{ this->cbc_mode,
this->cbc_block);
if (return_after_init) {
return; return;
} }
} }
this->crypto->rijndael_process(this->inbuf, this->outbuf); this->crypto->rijndael_process(this->inbuf, this->outbuf);
unsigned int bytes = this->buf_size; unsigned int bytes = this->buf_size;
if (strip_padding) if (strip_padding) {
{
unsigned char last = this->outbuf[this->buf_size - 1]; unsigned char last = this->outbuf[this->buf_size - 1];
if (last <= this->buf_size) if (last <= this->buf_size) {
{
bool strip = true; bool strip = true;
for (unsigned int i = 1; i <= last; ++i) for (unsigned int i = 1; i <= last; ++i) {
{ if (this->outbuf[this->buf_size - i] != last) {
if (this->outbuf[this->buf_size - i] != last)
{
strip = false; strip = false;
break; break;
} }
} }
if (strip) if (strip) {
{
bytes -= last; bytes -= last;
} }
} }

View File

@ -19,55 +19,41 @@ Pl_ASCII85Decoder::~Pl_ASCII85Decoder()
void void
Pl_ASCII85Decoder::write(unsigned char* buf, size_t len) Pl_ASCII85Decoder::write(unsigned char* buf, size_t len)
{ {
if (eod > 1) if (eod > 1) {
{
return; return;
} }
for (size_t i = 0; i < len; ++i) for (size_t i = 0; i < len; ++i) {
{ if (eod > 1) {
if (eod > 1)
{
break; break;
} } else if (eod == 1) {
else if (eod == 1) if (buf[i] == '>') {
{
if (buf[i] == '>')
{
flush(); flush();
eod = 2; eod = 2;
} } else {
else
{
throw std::runtime_error( throw std::runtime_error(
"broken end-of-data sequence in base 85 data"); "broken end-of-data sequence in base 85 data");
} }
} } else {
else switch (buf[i]) {
{ case ' ':
switch (buf[i]) case '\f':
{ case '\v':
case ' ': case '\t':
case '\f': case '\r':
case '\v': case '\n':
case '\t':
case '\r':
case '\n':
QTC::TC("libtests", "Pl_ASCII85Decoder ignore space"); QTC::TC("libtests", "Pl_ASCII85Decoder ignore space");
// ignore whitespace // ignore whitespace
break; break;
case '~': case '~':
eod = 1; eod = 1;
break; break;
case 'z': case 'z':
if (pos != 0) if (pos != 0) {
{
throw std::runtime_error( throw std::runtime_error(
"unexpected z during base 85 decode"); "unexpected z during base 85 decode");
} } else {
else
{
QTC::TC("libtests", "Pl_ASCII85Decoder read z"); QTC::TC("libtests", "Pl_ASCII85Decoder read z");
unsigned char zeroes[4]; unsigned char zeroes[4];
memset(zeroes, '\0', 4); memset(zeroes, '\0', 4);
@ -75,17 +61,13 @@ Pl_ASCII85Decoder::write(unsigned char* buf, size_t len)
} }
break; break;
default: default:
if ((buf[i] < 33) || (buf[i] > 117)) if ((buf[i] < 33) || (buf[i] > 117)) {
{
throw std::runtime_error( throw std::runtime_error(
"character out of range during base 85 decode"); "character out of range during base 85 decode");
} } else {
else
{
this->inbuf[this->pos++] = buf[i]; this->inbuf[this->pos++] = buf[i];
if (pos == 5) if (pos == 5) {
{
flush(); flush();
} }
} }
@ -98,28 +80,27 @@ Pl_ASCII85Decoder::write(unsigned char* buf, size_t len)
void void
Pl_ASCII85Decoder::flush() Pl_ASCII85Decoder::flush()
{ {
if (this->pos == 0) if (this->pos == 0) {
{
QTC::TC("libtests", "Pl_ASCII85Decoder no-op flush"); QTC::TC("libtests", "Pl_ASCII85Decoder no-op flush");
return; return;
} }
unsigned long lval = 0; unsigned long lval = 0;
for (int i = 0; i < 5; ++i) for (int i = 0; i < 5; ++i) {
{
lval *= 85; lval *= 85;
lval += (this->inbuf[i] - 33U); lval += (this->inbuf[i] - 33U);
} }
unsigned char outbuf[4]; unsigned char outbuf[4];
memset(outbuf, 0, 4); memset(outbuf, 0, 4);
for (int i = 3; i >= 0; --i) for (int i = 3; i >= 0; --i) {
{
outbuf[i] = lval & 0xff; outbuf[i] = lval & 0xff;
lval >>= 8; lval >>= 8;
} }
QTC::TC("libtests", "Pl_ASCII85Decoder partial flush", QTC::TC(
(this->pos == 5) ? 0 : 1); "libtests",
"Pl_ASCII85Decoder partial flush",
(this->pos == 5) ? 0 : 1);
// Reset before calling getNext()->write in case that throws an // Reset before calling getNext()->write in case that throws an
// exception. // exception.
auto t = this->pos - 1; auto t = this->pos - 1;

View File

@ -1,9 +1,9 @@
#include <qpdf/Pl_ASCIIHexDecoder.hh> #include <qpdf/Pl_ASCIIHexDecoder.hh>
#include <qpdf/QTC.hh> #include <qpdf/QTC.hh>
#include <ctype.h>
#include <stdexcept> #include <stdexcept>
#include <string.h> #include <string.h>
#include <ctype.h>
Pl_ASCIIHexDecoder::Pl_ASCIIHexDecoder(char const* identifier, Pipeline* next) : Pl_ASCIIHexDecoder::Pl_ASCIIHexDecoder(char const* identifier, Pipeline* next) :
Pipeline(identifier, next), Pipeline(identifier, next),
@ -22,53 +22,45 @@ Pl_ASCIIHexDecoder::~Pl_ASCIIHexDecoder()
void void
Pl_ASCIIHexDecoder::write(unsigned char* buf, size_t len) Pl_ASCIIHexDecoder::write(unsigned char* buf, size_t len)
{ {
if (this->eod) if (this->eod) {
{
return; return;
} }
for (size_t i = 0; i < len; ++i) for (size_t i = 0; i < len; ++i) {
{
char ch = static_cast<char>(toupper(buf[i])); char ch = static_cast<char>(toupper(buf[i]));
switch (ch) switch (ch) {
{ case ' ':
case ' ': case '\f':
case '\f': case '\v':
case '\v': case '\t':
case '\t': case '\r':
case '\r': case '\n':
case '\n':
QTC::TC("libtests", "Pl_ASCIIHexDecoder ignore space"); QTC::TC("libtests", "Pl_ASCIIHexDecoder ignore space");
// ignore whitespace // ignore whitespace
break; break;
case '>': case '>':
this->eod = true; this->eod = true;
flush(); flush();
break; break;
default: default:
if (((ch >= '0') && (ch <= '9')) || if (((ch >= '0') && (ch <= '9')) || ((ch >= 'A') && (ch <= 'F'))) {
((ch >= 'A') && (ch <= 'F')))
{
this->inbuf[this->pos++] = ch; this->inbuf[this->pos++] = ch;
if (this->pos == 2) if (this->pos == 2) {
{
flush(); flush();
} }
} } else {
else
{
char t[2]; char t[2];
t[0] = ch; t[0] = ch;
t[1] = 0; t[1] = 0;
throw std::runtime_error( throw std::runtime_error(
std::string("character out of range" std::string("character out of range"
" during base Hex decode: ") + t); " during base Hex decode: ") +
t);
} }
break; break;
} }
if (this->eod) if (this->eod) {
{
break; break;
} }
} }
@ -77,27 +69,24 @@ Pl_ASCIIHexDecoder::write(unsigned char* buf, size_t len)
void void
Pl_ASCIIHexDecoder::flush() Pl_ASCIIHexDecoder::flush()
{ {
if (this->pos == 0) if (this->pos == 0) {
{
QTC::TC("libtests", "Pl_ASCIIHexDecoder no-op flush"); QTC::TC("libtests", "Pl_ASCIIHexDecoder no-op flush");
return; return;
} }
int b[2]; int b[2];
for (int i = 0; i < 2; ++i) for (int i = 0; i < 2; ++i) {
{ if (this->inbuf[i] >= 'A') {
if (this->inbuf[i] >= 'A')
{
b[i] = this->inbuf[i] - 'A' + 10; b[i] = this->inbuf[i] - 'A' + 10;
} } else {
else
{
b[i] = this->inbuf[i] - '0'; b[i] = this->inbuf[i] - '0';
} }
} }
unsigned char ch = static_cast<unsigned char>((b[0] << 4) + b[1]); unsigned char ch = static_cast<unsigned char>((b[0] << 4) + b[1]);
QTC::TC("libtests", "Pl_ASCIIHexDecoder partial flush", QTC::TC(
(this->pos == 2) ? 0 : 1); "libtests",
"Pl_ASCIIHexDecoder partial flush",
(this->pos == 2) ? 0 : 1);
// Reset before calling getNext()->write in case that throws an // Reset before calling getNext()->write in case that throws an
// exception. // exception.
this->pos = 0; this->pos = 0;

View File

@ -1,10 +1,10 @@
#include <qpdf/Pl_Buffer.hh> #include <qpdf/Pl_Buffer.hh>
#include <stdexcept>
#include <algorithm> #include <algorithm>
#include <assert.h> #include <assert.h>
#include <string.h> #include <stdexcept>
#include <stdlib.h> #include <stdlib.h>
#include <string.h>
Pl_Buffer::Members::Members() : Pl_Buffer::Members::Members() :
ready(true), ready(true),
@ -29,28 +29,24 @@ Pl_Buffer::~Pl_Buffer()
void void
Pl_Buffer::write(unsigned char* buf, size_t len) Pl_Buffer::write(unsigned char* buf, size_t len)
{ {
if (this->m->data.get() == 0) if (this->m->data.get() == 0) {
{
this->m->data = make_pointer_holder<Buffer>(len); this->m->data = make_pointer_holder<Buffer>(len);
} }
size_t cur_size = this->m->data->getSize(); size_t cur_size = this->m->data->getSize();
size_t left = cur_size - this->m->total_size; size_t left = cur_size - this->m->total_size;
if (left < len) if (left < len) {
{
size_t new_size = std::max(this->m->total_size + len, 2 * cur_size); size_t new_size = std::max(this->m->total_size + len, 2 * cur_size);
auto b = make_pointer_holder<Buffer>(new_size); auto b = make_pointer_holder<Buffer>(new_size);
memcpy(b->getBuffer(), this->m->data->getBuffer(), this->m->total_size); memcpy(b->getBuffer(), this->m->data->getBuffer(), this->m->total_size);
this->m->data = b; this->m->data = b;
} }
if (len) if (len) {
{
memcpy(this->m->data->getBuffer() + this->m->total_size, buf, len); memcpy(this->m->data->getBuffer() + this->m->total_size, buf, len);
this->m->total_size += len; this->m->total_size += len;
} }
this->m->ready = false; this->m->ready = false;
if (getNext(true)) if (getNext(true)) {
{
getNext()->write(buf, len); getNext()->write(buf, len);
} }
} }
@ -59,8 +55,7 @@ void
Pl_Buffer::finish() Pl_Buffer::finish()
{ {
this->m->ready = true; this->m->ready = true;
if (getNext(true)) if (getNext(true)) {
{
getNext()->finish(); getNext()->finish();
} }
} }
@ -68,14 +63,12 @@ Pl_Buffer::finish()
Buffer* Buffer*
Pl_Buffer::getBuffer() Pl_Buffer::getBuffer()
{ {
if (! this->m->ready) if (!this->m->ready) {
{
throw std::logic_error("Pl_Buffer::getBuffer() called when not ready"); throw std::logic_error("Pl_Buffer::getBuffer() called when not ready");
} }
Buffer* b = new Buffer(this->m->total_size); Buffer* b = new Buffer(this->m->total_size);
if (this->m->total_size > 0) if (this->m->total_size > 0) {
{
unsigned char* p = b->getBuffer(); unsigned char* p = b->getBuffer();
memcpy(p, this->m->data->getBuffer(), this->m->total_size); memcpy(p, this->m->data->getBuffer(), this->m->total_size);
} }
@ -90,22 +83,18 @@ Pl_Buffer::getBufferSharedPointer()
} }
void void
Pl_Buffer::getMallocBuffer(unsigned char **buf, size_t* len) Pl_Buffer::getMallocBuffer(unsigned char** buf, size_t* len)
{ {
if (! this->m->ready) if (!this->m->ready) {
{
throw std::logic_error( throw std::logic_error(
"Pl_Buffer::getMallocBuffer() called when not ready"); "Pl_Buffer::getMallocBuffer() called when not ready");
} }
*len = this->m->total_size; *len = this->m->total_size;
if (this->m->total_size > 0) if (this->m->total_size > 0) {
{
*buf = reinterpret_cast<unsigned char*>(malloc(this->m->total_size)); *buf = reinterpret_cast<unsigned char*>(malloc(this->m->total_size));
memcpy(*buf, this->m->data->getBuffer(), this->m->total_size); memcpy(*buf, this->m->data->getBuffer(), this->m->total_size);
} } else {
else
{
*buf = nullptr; *buf = nullptr;
} }
this->m = PointerHolder<Members>(new Members()); this->m = PointerHolder<Members>(new Members());

View File

@ -33,4 +33,3 @@ Pl_Concatenate::manualFinish()
{ {
getNext()->finish(); getNext()->finish();
} }

View File

@ -25,8 +25,7 @@ Pl_Count::~Pl_Count()
void void
Pl_Count::write(unsigned char* buf, size_t len) Pl_Count::write(unsigned char* buf, size_t len)
{ {
if (len) if (len) {
{
this->m->count += QIntC::to_offset(len); this->m->count += QIntC::to_offset(len);
this->m->last_char = buf[len - 1]; this->m->last_char = buf[len - 1];
getNext()->write(buf, len); getNext()->write(buf, len);

View File

@ -1,14 +1,14 @@
#include <qpdf/Pl_DCT.hh> #include <qpdf/Pl_DCT.hh>
#include <qpdf/QUtil.hh>
#include <qpdf/QTC.hh>
#include <qpdf/QIntC.hh> #include <qpdf/QIntC.hh>
#include <qpdf/QTC.hh>
#include <qpdf/QUtil.hh>
#include <cstring>
#include <setjmp.h> #include <setjmp.h>
#include <stdexcept> #include <stdexcept>
#include <stdlib.h> #include <stdlib.h>
#include <string> #include <string>
#include <cstring>
#if BITS_IN_JSAMPLE != 8 #if BITS_IN_JSAMPLE != 8
# error "qpdf does not support libjpeg built with BITS_IN_JSAMPLE != 8" # error "qpdf does not support libjpeg built with BITS_IN_JSAMPLE != 8"
@ -32,13 +32,14 @@ error_handler(j_common_ptr cinfo)
longjmp(jerr->jmpbuf, 1); longjmp(jerr->jmpbuf, 1);
} }
Pl_DCT::Members::Members(action_e action, Pl_DCT::Members::Members(
char const* buf_description, action_e action,
JDIMENSION image_width, char const* buf_description,
JDIMENSION image_height, JDIMENSION image_width,
int components, JDIMENSION image_height,
J_COLOR_SPACE color_space, int components,
CompressConfig* config_callback) : J_COLOR_SPACE color_space,
CompressConfig* config_callback) :
action(action), action(action),
buf(buf_description), buf(buf_description),
image_width(image_width), image_width(image_width),
@ -59,15 +60,23 @@ Pl_DCT::Pl_DCT(char const* identifier, Pipeline* next) :
{ {
} }
Pl_DCT::Pl_DCT(char const* identifier, Pipeline* next, Pl_DCT::Pl_DCT(
JDIMENSION image_width, char const* identifier,
JDIMENSION image_height, Pipeline* next,
int components, JDIMENSION image_width,
J_COLOR_SPACE color_space, JDIMENSION image_height,
CompressConfig* config_callback) : int components,
J_COLOR_SPACE color_space,
CompressConfig* config_callback) :
Pipeline(identifier, next), Pipeline(identifier, next),
m(new Members(a_compress, "DCT uncompressed image", m(new Members(
image_width, image_height, components, color_space, config_callback)) a_compress,
"DCT uncompressed image",
image_width,
image_height,
components,
color_space,
config_callback))
{ {
} }
@ -90,8 +99,7 @@ Pl_DCT::finish()
// and decompress causes a memory leak with setjmp/longjmp. Just // and decompress causes a memory leak with setjmp/longjmp. Just
// use a pointer and delete it. // use a pointer and delete it.
Buffer* b = this->m->buf.getBuffer(); Buffer* b = this->m->buf.getBuffer();
if (b->getSize() == 0) if (b->getSize() == 0) {
{
// Special case: empty data will never succeed and probably // Special case: empty data will never succeed and probably
// means we're calling finish a second time from an exception // means we're calling finish a second time from an exception
// handler. // handler.
@ -111,44 +119,32 @@ Pl_DCT::finish()
bool error = false; bool error = false;
// The jpeg library is a "C" library, so we use setjmp and longjmp // The jpeg library is a "C" library, so we use setjmp and longjmp
// for exception handling. // for exception handling.
if (setjmp(jerr.jmpbuf) == 0) if (setjmp(jerr.jmpbuf) == 0) {
{ try {
try if (this->m->action == a_compress) {
{
if (this->m->action == a_compress)
{
compress(reinterpret_cast<void*>(&cinfo_compress), b); compress(reinterpret_cast<void*>(&cinfo_compress), b);
} } else {
else
{
decompress(reinterpret_cast<void*>(&cinfo_decompress), b); decompress(reinterpret_cast<void*>(&cinfo_decompress), b);
} }
} } catch (std::exception& e) {
catch (std::exception& e)
{
// Convert an exception back to a longjmp so we can ensure // Convert an exception back to a longjmp so we can ensure
// that the right cleanup happens. This will get converted // that the right cleanup happens. This will get converted
// back to an exception. // back to an exception.
jerr.msg = e.what(); jerr.msg = e.what();
longjmp(jerr.jmpbuf, 1); longjmp(jerr.jmpbuf, 1);
} }
} } else {
else
{
error = true; error = true;
} }
delete b; delete b;
if (this->m->action == a_compress) if (this->m->action == a_compress) {
{
jpeg_destroy_compress(&cinfo_compress); jpeg_destroy_compress(&cinfo_compress);
} }
if (this->m->action == a_decompress) if (this->m->action == a_decompress) {
{
jpeg_destroy_decompress(&cinfo_decompress); jpeg_destroy_decompress(&cinfo_decompress);
} }
if (error) if (error) {
{
throw std::runtime_error(jerr.msg); throw std::runtime_error(jerr.msg);
} }
} }
@ -170,8 +166,7 @@ static boolean
empty_pipeline_output_buffer(j_compress_ptr cinfo) empty_pipeline_output_buffer(j_compress_ptr cinfo)
{ {
QTC::TC("libtests", "Pl_DCT empty_pipeline_output_buffer"); QTC::TC("libtests", "Pl_DCT empty_pipeline_output_buffer");
dct_pipeline_dest* dest = dct_pipeline_dest* dest = reinterpret_cast<dct_pipeline_dest*>(cinfo->dest);
reinterpret_cast<dct_pipeline_dest*>(cinfo->dest);
dest->next->write(dest->buffer, dest->size); dest->next->write(dest->buffer, dest->size);
dest->pub.next_output_byte = dest->buffer; dest->pub.next_output_byte = dest->buffer;
dest->pub.free_in_buffer = dest->size; dest->pub.free_in_buffer = dest->size;
@ -182,22 +177,20 @@ static void
term_pipeline_destination(j_compress_ptr cinfo) term_pipeline_destination(j_compress_ptr cinfo)
{ {
QTC::TC("libtests", "Pl_DCT term_pipeline_destination"); QTC::TC("libtests", "Pl_DCT term_pipeline_destination");
dct_pipeline_dest* dest = dct_pipeline_dest* dest = reinterpret_cast<dct_pipeline_dest*>(cinfo->dest);
reinterpret_cast<dct_pipeline_dest*>(cinfo->dest);
dest->next->write(dest->buffer, dest->size - dest->pub.free_in_buffer); dest->next->write(dest->buffer, dest->size - dest->pub.free_in_buffer);
} }
static void static void
jpeg_pipeline_dest(j_compress_ptr cinfo, jpeg_pipeline_dest(
unsigned char* outbuffer, size_t size, j_compress_ptr cinfo, unsigned char* outbuffer, size_t size, Pipeline* next)
Pipeline* next)
{ {
cinfo->dest = static_cast<struct jpeg_destination_mgr *>( cinfo->dest =
(*cinfo->mem->alloc_small)(reinterpret_cast<j_common_ptr>(cinfo), static_cast<struct jpeg_destination_mgr*>((*cinfo->mem->alloc_small)(
JPOOL_PERMANENT, reinterpret_cast<j_common_ptr>(cinfo),
sizeof(dct_pipeline_dest))); JPOOL_PERMANENT,
dct_pipeline_dest* dest = sizeof(dct_pipeline_dest)));
reinterpret_cast<dct_pipeline_dest*>(cinfo->dest); dct_pipeline_dest* dest = reinterpret_cast<dct_pipeline_dest*>(cinfo->dest);
dest->pub.init_destination = init_pipeline_destination; dest->pub.init_destination = init_pipeline_destination;
dest->pub.empty_output_buffer = empty_pipeline_output_buffer; dest->pub.empty_output_buffer = empty_pipeline_output_buffer;
dest->pub.term_destination = term_pipeline_destination; dest->pub.term_destination = term_pipeline_destination;
@ -224,20 +217,15 @@ fill_buffer_input_buffer(j_decompress_ptr)
static void static void
skip_buffer_input_data(j_decompress_ptr cinfo, long num_bytes) skip_buffer_input_data(j_decompress_ptr cinfo, long num_bytes)
{ {
if (num_bytes < 0) if (num_bytes < 0) {
{ throw std::runtime_error("reading jpeg: jpeg library requested"
throw std::runtime_error( " skipping a negative number of bytes");
"reading jpeg: jpeg library requested"
" skipping a negative number of bytes");
} }
size_t to_skip = QIntC::to_size(num_bytes); size_t to_skip = QIntC::to_size(num_bytes);
if ((to_skip > 0) && (to_skip <= cinfo->src->bytes_in_buffer)) if ((to_skip > 0) && (to_skip <= cinfo->src->bytes_in_buffer)) {
{
cinfo->src->next_input_byte += to_skip; cinfo->src->next_input_byte += to_skip;
cinfo->src->bytes_in_buffer -= to_skip; cinfo->src->bytes_in_buffer -= to_skip;
} } else if (to_skip != 0) {
else if (to_skip != 0)
{
cinfo->src->next_input_byte += cinfo->src->bytes_in_buffer; cinfo->src->next_input_byte += cinfo->src->bytes_in_buffer;
cinfo->src->bytes_in_buffer = 0; cinfo->src->bytes_in_buffer = 0;
} }
@ -251,10 +239,10 @@ term_buffer_source(j_decompress_ptr)
static void static void
jpeg_buffer_src(j_decompress_ptr cinfo, Buffer* buffer) jpeg_buffer_src(j_decompress_ptr cinfo, Buffer* buffer)
{ {
cinfo->src = reinterpret_cast<jpeg_source_mgr *>( cinfo->src = reinterpret_cast<jpeg_source_mgr*>((*cinfo->mem->alloc_small)(
(*cinfo->mem->alloc_small)(reinterpret_cast<j_common_ptr>(cinfo), reinterpret_cast<j_common_ptr>(cinfo),
JPOOL_PERMANENT, JPOOL_PERMANENT,
sizeof(jpeg_source_mgr))); sizeof(jpeg_source_mgr)));
jpeg_source_mgr* src = cinfo->src; jpeg_source_mgr* src = cinfo->src;
src->init_source = init_buffer_source; src->init_source = init_buffer_source;
@ -272,15 +260,17 @@ Pl_DCT::compress(void* cinfo_p, Buffer* b)
struct jpeg_compress_struct* cinfo = struct jpeg_compress_struct* cinfo =
reinterpret_cast<jpeg_compress_struct*>(cinfo_p); reinterpret_cast<jpeg_compress_struct*>(cinfo_p);
#if ((defined(__GNUC__) && ((__GNUC__ * 100) + __GNUC_MINOR__) >= 406) || \ #if ( \
defined(__clang__)) (defined(__GNUC__) && ((__GNUC__ * 100) + __GNUC_MINOR__) >= 406) || \
# pragma GCC diagnostic push defined(__clang__))
# pragma GCC diagnostic ignored "-Wold-style-cast" # pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wold-style-cast"
#endif #endif
jpeg_create_compress(cinfo); jpeg_create_compress(cinfo);
#if ((defined(__GNUC__) && ((__GNUC__ * 100) + __GNUC_MINOR__) >= 406) || \ #if ( \
defined(__clang__)) (defined(__GNUC__) && ((__GNUC__ * 100) + __GNUC_MINOR__) >= 406) || \
# pragma GCC diagnostic pop defined(__clang__))
# pragma GCC diagnostic pop
#endif #endif
static int const BUF_SIZE = 65536; static int const BUF_SIZE = 65536;
auto outbuffer_ph = std::make_unique<unsigned char[]>(BUF_SIZE); auto outbuffer_ph = std::make_unique<unsigned char[]>(BUF_SIZE);
@ -292,33 +282,29 @@ Pl_DCT::compress(void* cinfo_p, Buffer* b)
cinfo->input_components = this->m->components; cinfo->input_components = this->m->components;
cinfo->in_color_space = this->m->color_space; cinfo->in_color_space = this->m->color_space;
jpeg_set_defaults(cinfo); jpeg_set_defaults(cinfo);
if (this->m->config_callback) if (this->m->config_callback) {
{
this->m->config_callback->apply(cinfo); this->m->config_callback->apply(cinfo);
} }
jpeg_start_compress(cinfo, TRUE); jpeg_start_compress(cinfo, TRUE);
unsigned int width = cinfo->image_width * unsigned int width =
QIntC::to_uint(cinfo->input_components); cinfo->image_width * QIntC::to_uint(cinfo->input_components);
size_t expected_size = size_t expected_size = QIntC::to_size(cinfo->image_height) *
QIntC::to_size(cinfo->image_height) *
QIntC::to_size(cinfo->image_width) * QIntC::to_size(cinfo->image_width) *
QIntC::to_size(cinfo->input_components); QIntC::to_size(cinfo->input_components);
if (b->getSize() != expected_size) if (b->getSize() != expected_size) {
{
throw std::runtime_error( throw std::runtime_error(
"Pl_DCT: image buffer size = " + "Pl_DCT: image buffer size = " +
QUtil::uint_to_string(b->getSize()) + "; expected size = " + QUtil::uint_to_string(b->getSize()) +
QUtil::uint_to_string(expected_size)); "; expected size = " + QUtil::uint_to_string(expected_size));
} }
JSAMPROW row_pointer[1]; JSAMPROW row_pointer[1];
unsigned char* buffer = b->getBuffer(); unsigned char* buffer = b->getBuffer();
while (cinfo->next_scanline < cinfo->image_height) while (cinfo->next_scanline < cinfo->image_height) {
{
// We already verified that the buffer is big enough. // We already verified that the buffer is big enough.
row_pointer[0] = &buffer[cinfo->next_scanline * width]; row_pointer[0] = &buffer[cinfo->next_scanline * width];
(void) jpeg_write_scanlines(cinfo, row_pointer, 1); (void)jpeg_write_scanlines(cinfo, row_pointer, 1);
} }
jpeg_finish_compress(cinfo); jpeg_finish_compress(cinfo);
this->getNext()->finish(); this->getNext()->finish();
@ -330,33 +316,35 @@ Pl_DCT::decompress(void* cinfo_p, Buffer* b)
struct jpeg_decompress_struct* cinfo = struct jpeg_decompress_struct* cinfo =
reinterpret_cast<jpeg_decompress_struct*>(cinfo_p); reinterpret_cast<jpeg_decompress_struct*>(cinfo_p);
#if ((defined(__GNUC__) && ((__GNUC__ * 100) + __GNUC_MINOR__) >= 406) || \ #if ( \
defined(__clang__)) (defined(__GNUC__) && ((__GNUC__ * 100) + __GNUC_MINOR__) >= 406) || \
# pragma GCC diagnostic push defined(__clang__))
# pragma GCC diagnostic ignored "-Wold-style-cast" # pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wold-style-cast"
#endif #endif
jpeg_create_decompress(cinfo); jpeg_create_decompress(cinfo);
#if ((defined(__GNUC__) && ((__GNUC__ * 100) + __GNUC_MINOR__) >= 406) || \ #if ( \
defined(__clang__)) (defined(__GNUC__) && ((__GNUC__ * 100) + __GNUC_MINOR__) >= 406) || \
# pragma GCC diagnostic pop defined(__clang__))
# pragma GCC diagnostic pop
#endif #endif
jpeg_buffer_src(cinfo, b); jpeg_buffer_src(cinfo, b);
(void) jpeg_read_header(cinfo, TRUE); (void)jpeg_read_header(cinfo, TRUE);
(void) jpeg_calc_output_dimensions(cinfo); (void)jpeg_calc_output_dimensions(cinfo);
unsigned int width = cinfo->output_width * unsigned int width =
QIntC::to_uint(cinfo->output_components); cinfo->output_width * QIntC::to_uint(cinfo->output_components);
JSAMPARRAY buffer = (*cinfo->mem->alloc_sarray) JSAMPARRAY buffer = (*cinfo->mem->alloc_sarray)(
(reinterpret_cast<j_common_ptr>(cinfo), JPOOL_IMAGE, width, 1); reinterpret_cast<j_common_ptr>(cinfo), JPOOL_IMAGE, width, 1);
(void) jpeg_start_decompress(cinfo); (void)jpeg_start_decompress(cinfo);
while (cinfo->output_scanline < cinfo->output_height) while (cinfo->output_scanline < cinfo->output_height) {
{ (void)jpeg_read_scanlines(cinfo, buffer, 1);
(void) jpeg_read_scanlines(cinfo, buffer, 1); this->getNext()->write(
this->getNext()->write(reinterpret_cast<unsigned char*>(buffer[0]), reinterpret_cast<unsigned char*>(buffer[0]),
width * sizeof(buffer[0][0])); width * sizeof(buffer[0][0]));
} }
(void) jpeg_finish_decompress(cinfo); (void)jpeg_finish_decompress(cinfo);
this->getNext()->finish(); this->getNext()->finish();
} }

Some files were not shown because too many files have changed in this diff Show More