2
1
mirror of https://github.com/qpdf/qpdf.git synced 2024-12-22 10:58:58 +00:00

Rerun clang-format

This commit is contained in:
Jay Berkenbilt 2023-05-21 13:35:09 -04:00
parent 6b077332d3
commit 60965d5f4d
196 changed files with 2594 additions and 5614 deletions

View File

@ -71,8 +71,7 @@ process(
// Create a file spec. // Create a file spec.
std::string key = QUtil::path_basename(attachment); std::string key = QUtil::path_basename(attachment);
std::cout << whoami << ": attaching " << attachment << " as " << key std::cout << whoami << ": attaching " << attachment << " as " << key << std::endl;
<< std::endl;
auto fs = QPDFFileSpecObjectHelper::createFileSpec(q, key, attachment); auto fs = QPDFFileSpecObjectHelper::createFileSpec(q, key, attachment);
if (mimetype) { if (mimetype) {

View File

@ -23,16 +23,12 @@ static std::map<QPDFObjGen, int> page_map;
void void
usage() usage()
{ {
std::cerr std::cerr << "Usage: " << whoami << " [options] file.pdf [password]" << std::endl
<< "Usage: " << whoami << " [options] file.pdf [password]" << std::endl << "Options:" << std::endl
<< "Options:" << std::endl << " --numbers give bookmarks outline-style numbers" << std::endl
<< " --numbers give bookmarks outline-style numbers" << " --lines draw lines to show bookmark hierarchy" << std::endl
<< std::endl << " --show-open indicate whether a bookmark is initially open" << std::endl
<< " --lines draw lines to show bookmark hierarchy" << " --show-targets show target if possible" << std::endl;
<< std::endl
<< " --show-open indicate whether a bookmark is initially open"
<< std::endl
<< " --show-targets show target if possible" << std::endl;
exit(2); exit(2);
} }
@ -120,16 +116,14 @@ show_bookmark_details(QPDFOutlineObjectHelper outline, std::vector<int> numbers)
} }
void void
extract_bookmarks( extract_bookmarks(std::vector<QPDFOutlineObjectHelper> outlines, std::vector<int>& numbers)
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.
// For style == st_lines, numbers.at(n) == 0 indicates the last // For style == st_lines, numbers.at(n) == 0 indicates the last
// outline at level n, and we don't otherwise care what the value // outline at level n, and we don't otherwise care what the value
// 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);
@ -196,8 +190,7 @@ main(int argc, char* argv[])
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

@ -33,8 +33,7 @@ modify_file(qpdf_data qpdf)
qpdf_oh_remove_key(qpdf, root, "/OpenAction"); qpdf_oh_remove_key(qpdf, root, "/OpenAction");
/* 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);
@ -71,8 +70,7 @@ main(int argc, char* argv[])
password = argv[2]; password = argv[2];
outfile = argv[3]; outfile = argv[3];
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
@ -82,15 +80,11 @@ main(int argc, char* argv[])
} }
while (qpdf_more_warnings(qpdf)) { while (qpdf_more_warnings(qpdf)) {
warnings = 1; warnings = 1;
printf( printf("warning: %s\n", 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( printf("error: %s\n", 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) {

View File

@ -97,8 +97,7 @@ main(int argc, char* argv[])
page.filterContents(&counter, &out); page.filterContents(&counter, &out);
std::cout << "\n% end " << pageno << std::endl; std::cout << "\n% end " << pageno << std::endl;
} }
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;

View File

@ -41,8 +41,7 @@ class ImageProvider: public QPDFObjectHandle::StreamDataProvider
J_COLOR_SPACE j_color_space; J_COLOR_SPACE j_color_space;
}; };
ImageProvider::ImageProvider( ImageProvider::ImageProvider(std::string const& color_space, 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),
@ -107,8 +106,7 @@ ImageProvider::provideStreamData(QPDFObjGen const&, Pipeline* pipeline)
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();
} }
@ -184,8 +182,7 @@ add_page(
image.replaceDict(image_dict); image.replaceDict(image_dict);
// Provide the stream data. // Provide the stream data.
image.replaceStreamData( image.replaceStreamData(provider, QPDFObjectHandle::parse(filter), QPDFObjectHandle::newNull());
provider, QPDFObjectHandle::parse(filter), 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;
@ -202,8 +199,7 @@ add_page(
resources.replaceKey("/XObject", xobject); resources.replaceKey("/XObject", xobject);
// Create the page content stream // Create the page content stream
QPDFObjectHandle contents = QPDFObjectHandle contents = createPageContents(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("<<"
@ -256,8 +252,7 @@ check(
} }
// Check filter and color space. // Check filter and color space.
std::string desired_color_space = std::string desired_color_space = color_spaces[(pageno - 1) / n_color_spaces];
color_spaces[(pageno - 1) / n_color_spaces];
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.
@ -271,16 +266,13 @@ check(
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
<< desired_filter
<< "; actual 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
<< desired_color_space << "; actual color space = " << color_space.unparse() << std::endl;
<< "; actual color space = " << color_space.unparse()
<< std::endl;
} }
if (!this_errors) { if (!this_errors) {
@ -293,8 +285,7 @@ check(
std::shared_ptr<Buffer> desired_data(b_p.getBuffer()); std::shared_ptr<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 << ": image data length mismatch" << std::endl;
<< 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
@ -308,8 +299,7 @@ check(
size_t len = actual_data->getSize(); size_t len = actual_data->getSize();
unsigned int mismatches = 0; unsigned int mismatches = 0;
int tolerance = (desired_filter == "/DCTDecode" ? 10 : 0); int tolerance = (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)) {
@ -317,9 +307,8 @@ check(
} }
} }
if (mismatches > threshold) { if (mismatches > threshold) {
std::cout << "page " << pageno << ": " std::cout << "page " << pageno << ": " << desired_color_space << ", "
<< desired_color_space << ", " << desired_filter << desired_filter << ": mismatches: " << mismatches << " of " << len
<< ": mismatches: " << mismatches << " of " << len
<< std::endl; << std::endl;
this_errors = errors = true; this_errors = errors = true;
} }

View File

@ -132,8 +132,7 @@ SF_XORDecode::setDecodeParms(QPDFObjectHandle decode_parms)
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::cerr << "Error extracting key for /XORDecode: " << e.what() << std::endl;
<< std::endl;
} }
return false; return false;
} }
@ -203,8 +202,7 @@ class StreamReplacer: public QPDFObjectHandle::StreamDataProvider
void provideStreamData(QPDFObjGen const& og, Pipeline* pipeline) override; void provideStreamData(QPDFObjGen const& og, Pipeline* pipeline) override;
void registerStream( void registerStream(
QPDFObjectHandle stream, QPDFObjectHandle stream, std::shared_ptr<QPDFObjectHandle::StreamDataProvider> self);
std::shared_ptr<QPDFObjectHandle::StreamDataProvider> self);
private: private:
bool maybeReplace( bool maybeReplace(
@ -300,12 +298,10 @@ StreamReplacer::maybeReplace(
// 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", "/OrigLength", QPDFObjectHandle::newInteger(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) {
@ -319,8 +315,7 @@ StreamReplacer::maybeReplace(
void void
StreamReplacer::registerStream( StreamReplacer::registerStream(
QPDFObjectHandle stream, QPDFObjectHandle stream, std::shared_ptr<QPDFObjectHandle::StreamDataProvider> self)
std::shared_ptr<QPDFObjectHandle::StreamDataProvider> self)
{ {
QPDFObjGen og(stream.getObjGen()); QPDFObjGen og(stream.getObjGen());
@ -344,8 +339,7 @@ StreamReplacer::registerStream(
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: ") + e.what());
std::string("exception while attempting to replace: ") + e.what());
} }
if (should_replace) { if (should_replace) {
@ -369,8 +363,7 @@ StreamReplacer::registerStream(
// /XORDecode filter. // /XORDecode filter.
QPDFObjectHandle decode_parms = QPDFObjectHandle decode_parms =
QPDFObjectHandle::newDictionary({{"/KeyStream", dp_stream}}); QPDFObjectHandle::newDictionary({{"/KeyStream", dp_stream}});
stream.replaceStreamData( stream.replaceStreamData(self, QPDFObjectHandle::newName("/XORDecode"), decode_parms);
self, 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.
@ -393,14 +386,12 @@ StreamReplacer::provideStreamData(QPDFObjGen const& og, Pipeline* pipeline)
// 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.
throw std::logic_error( throw std::logic_error("should_replace return false in provideStreamData");
"should_replace return false in provideStreamData");
} }
} }
static void static void
process( process(char const* infilename, char const* outfilename, bool decode_specialized)
char const* infilename, char const* outfilename, bool decode_specialized)
{ {
QPDF qpdf; QPDF qpdf;
qpdf.processFile(infilename); qpdf.processFile(infilename);
@ -434,8 +425,7 @@ static void
usage() usage()
{ {
std::cerr << "\n" std::cerr << "\n"
<< "Usage: " << whoami << "Usage: " << whoami << " [--decode-specialized] infile outfile\n"
<< " [--decode-specialized] infile outfile\n"
<< std::endl; << std::endl;
exit(2); exit(2);
} }
@ -468,8 +458,7 @@ main(int argc, char* argv[])
// 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) {

View File

@ -13,8 +13,7 @@ static char const* whoami = nullptr;
void void
usage() 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
<< "Double size of all pages in infile.pdf;" << "Double size of all pages in infile.pdf;"
<< " write output to outfile.pdf" << std::endl; << " write output to outfile.pdf" << std::endl;
exit(2); exit(2);
@ -33,16 +32,13 @@ doubleBoxSize(QPDFPageObjectHelper& page, char const* box_name)
} }
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().replaceKey( page.getObjectHandle().replaceKey(box_name, QPDFObjectHandle::newArray(doubled));
box_name, QPDFObjectHandle::newArray(doubled));
} }
int int
@ -93,11 +89,9 @@ main(int argc, char* argv[])
w.setStreamDataMode(qpdf_s_uncompress); w.setStreamDataMode(qpdf_s_uncompress);
} }
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

@ -22,8 +22,7 @@ void
usage() 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" << std::endl;
<< std::endl;
exit(2); exit(2);
} }
@ -82,17 +81,13 @@ class ColorToGray: public QPDFObjectHandle::TokenFilter
bool bool
ColorToGray::isNumeric(QPDFTokenizer::token_type_e token_type) ColorToGray::isNumeric(QPDFTokenizer::token_type_e token_type)
{ {
return ( return ((token_type == QPDFTokenizer::tt_integer) || (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 ( return ((token_type == QPDFTokenizer::tt_space) || (token_type == QPDFTokenizer::tt_comment));
(token_type == QPDFTokenizer::tt_space) ||
(token_type == QPDFTokenizer::tt_comment));
} }
double double
@ -128,8 +123,7 @@ 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();
} }
@ -138,8 +132,7 @@ ColorToGray::handleToken(QPDFTokenizer::Token const& token)
if (!isIgnorable(token_type)) { if (!isIgnorable(token_type)) {
this->stack.push_back(token); this->stack.push_back(token);
if ((this->stack.size() == 4) && token.isWord("rg") && if ((this->stack.size() == 4) && token.isWord("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));
@ -195,11 +188,9 @@ main(int argc, char* argv[])
// applied. See comments on the filters for additional // applied. See comments on the filters for additional
// details. // details.
page.addContentTokenFilter( page.addContentTokenFilter(
std::shared_ptr<QPDFObjectHandle::TokenFilter>( std::shared_ptr<QPDFObjectHandle::TokenFilter>(new StringReverser));
new StringReverser));
page.addContentTokenFilter( page.addContentTokenFilter(
std::shared_ptr<QPDFObjectHandle::TokenFilter>( std::shared_ptr<QPDFObjectHandle::TokenFilter>(new ColorToGray));
new ColorToGray));
} }
QPDFWriter w(pdf, outfilename); QPDFWriter w(pdf, outfilename);

View File

@ -14,8 +14,7 @@ static char const* whoami = nullptr;
void void
usage() 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
<< "Invert some images in infile.pdf;" << "Invert some images in infile.pdf;"
<< " write output to outfile.pdf" << std::endl; << " write output to outfile.pdf" << std::endl;
exit(2); exit(2);
@ -37,8 +36,7 @@ class ImageInverter: public QPDFObjectHandle::StreamDataProvider
void provideStreamData(QPDFObjGen const& og, Pipeline* pipeline) override; void provideStreamData(QPDFObjGen const& og, Pipeline* pipeline) override;
void registerImage( void registerImage(
QPDFObjectHandle image, QPDFObjectHandle image, std::shared_ptr<QPDFObjectHandle::StreamDataProvider> self);
std::shared_ptr<QPDFObjectHandle::StreamDataProvider> self);
private: private:
std::map<QPDFObjGen, QPDFObjectHandle> copied_images; std::map<QPDFObjGen, QPDFObjectHandle> copied_images;
@ -46,8 +44,7 @@ class ImageInverter: public QPDFObjectHandle::StreamDataProvider
void void
ImageInverter::registerImage( ImageInverter::registerImage(
QPDFObjectHandle image, QPDFObjectHandle image, std::shared_ptr<QPDFObjectHandle::StreamDataProvider> self)
std::shared_ptr<QPDFObjectHandle::StreamDataProvider> self)
{ {
// replaceStreamData requires a pointer holder to the stream data // replaceStreamData requires a pointer holder to the stream data
// provider, but there's no way for us to generate one ourselves, // provider, but there's no way for us to generate one ourselves,
@ -76,8 +73,7 @@ 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( image.replaceStreamData(self, QPDFObjectHandle::newNull(), QPDFObjectHandle::newNull());
self, QPDFObjectHandle::newNull(), QPDFObjectHandle::newNull());
} }
void void
@ -86,8 +82,7 @@ ImageInverter::provideStreamData(QPDFObjGen const& og, 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
// data to the pipeline. // data to the pipeline.
std::shared_ptr<Buffer> data = std::shared_ptr<Buffer> data = this->copied_images[og].getStreamData(qpdf_dl_all);
this->copied_images[og].getStreamData(qpdf_dl_all);
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;
@ -133,18 +128,15 @@ main(int argc, char* argv[])
QPDFObjectHandle& image = iter.second; QPDFObjectHandle& image = iter.second;
QPDFObjectHandle image_dict = image.getDict(); QPDFObjectHandle image_dict = image.getDict();
QPDFObjectHandle color_space = image_dict.getKey("/ColorSpace"); QPDFObjectHandle color_space = image_dict.getKey("/ColorSpace");
QPDFObjectHandle bits_per_component = QPDFObjectHandle bits_per_component = image_dict.getKey("/BitsPerComponent");
image_dict.getKey("/BitsPerComponent");
// For our example, we can only work with images 8-bit // For our example, we can only work with images 8-bit
// grayscale images that we can fully decode. Use // grayscale images that we can fully decode. Use
// 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( if (image.pipeStreamData(nullptr, qpdf_ef_compress, qpdf_dl_all) &&
nullptr, qpdf_ef_compress, qpdf_dl_all) && color_space.isNameAndEquals("/DeviceGray") && bits_per_component.isInteger() &&
color_space.isNameAndEquals("/DeviceGray") &&
bits_per_component.isInteger() &&
(bits_per_component.getIntValue() == 8)) { (bits_per_component.getIntValue() == 8)) {
inv->registerImage(image, p); inv->registerImage(image, p);
} }
@ -159,11 +151,9 @@ main(int argc, char* argv[])
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;
} 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

@ -61,15 +61,11 @@ main(int argc, char* argv[])
} }
while (qpdf_more_warnings(qpdf)) { while (qpdf_more_warnings(qpdf)) {
warnings = 1; warnings = 1;
printf( printf("warning: %s\n", 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( printf("error: %s\n", 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) {

View File

@ -16,8 +16,7 @@ static char const* whoami = nullptr;
void void
usage() usage()
{ {
std::cerr << "Usage: " << whoami std::cerr << "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"
@ -26,8 +25,7 @@ usage()
} }
void void
dumpInfoDict( dumpInfoDict(QPDF& pdf, std::ostream& os = std::cout, 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")) {
@ -164,8 +162,7 @@ main(int argc, char* argv[])
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

@ -11,8 +11,7 @@ void
usage() usage()
{ {
std::cerr << "Usage: " << whoami << " outfile.pdf" << std::endl std::cerr << "Usage: " << whoami << " outfile.pdf" << 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);
} }
@ -61,24 +60,19 @@ 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 = auto iter = name_tree.insert("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;
--iter; --iter;
std::cout << "predecessor: " << iter->first << " -> " std::cout << "predecessor: " << iter->first << " -> " << iter->second.unparse() << std::endl;
<< iter->second.unparse() << std::endl;
++iter; ++iter;
++iter; ++iter;
std::cout << "successor: " << iter->first << " -> " std::cout << "successor: " << iter->first << " -> " << iter->second.unparse() << std::endl;
<< iter->second.unparse() << std::endl;
// 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 << " -> " << i.second.unparse() << std::endl;
<< 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
@ -107,14 +101,13 @@ 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 << " -> " << iter->second.unparse() std::cout << "Q: " << iter->first << " -> " << 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
iter = name_tree.find("W", true); iter = name_tree.find("W", true);
std::cout << "W's predecessor: " << iter->first << " -> " std::cout << "W's predecessor: " << iter->first << " -> " << iter->second.unparse()
<< iter->second.unparse() << std::endl; << std::endl;
// We can also remove items // We can also remove items
std::cout << "Remove P: " << name_tree.remove("P", &obj) << std::endl; std::cout << "Remove P: " << name_tree.remove("P", &obj) << std::endl;
@ -124,8 +117,8 @@ main(int argc, char* argv[])
iter = name_tree.find("K"); iter = name_tree.find("K");
std::cout << "Find K: " << iter->second.unparse() << std::endl; std::cout << "Find K: " << iter->second.unparse() << std::endl;
iter.remove(); iter.remove();
std::cout << "Iter after removing K: " << iter->first << " -> " std::cout << "Iter after removing K: " << iter->first << " -> " << iter->second.unparse()
<< iter->second.unparse() << std::endl; << std::endl;
std::cout << "Has K?: " << name_tree.hasName("K") << std::endl; std::cout << "Has K?: " << name_tree.hasName("K") << std::endl;
// Illustrate some more advanced usage using number trees. These // Illustrate some more advanced usage using number trees. These
@ -142,8 +135,7 @@ main(int argc, char* argv[])
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("-" + std::to_string(i) + "-"));
i, QPDFObjectHandle::newString("-" + std::to_string(i) + "-"));
} }
std::cout << "Numbers:" << std::endl; std::cout << "Numbers:" << std::endl;
int n = 1; int n = 1;

View File

@ -31,8 +31,7 @@ stamp_page(char const* infile, char const* stampfile, char const* outfile)
stamppdf.processFile(stampfile); stamppdf.processFile(stampfile);
// Get first page from other file // Get first page from other file
QPDFPageObjectHelper stamp_page_1 = QPDFPageObjectHelper stamp_page_1 = QPDFPageDocumentHelper(stamppdf).getAllPages().at(0);
QPDFPageDocumentHelper(stamppdf).getAllPages().at(0);
// Convert page to a form XObject // Convert page to a form XObject
QPDFObjectHandle foreign_fo = stamp_page_1.getFormXObjectForPage(); QPDFObjectHandle foreign_fo = stamp_page_1.getFormXObjectForPage();
// Copy form XObject to the input file // Copy form XObject to the input file
@ -48,8 +47,8 @@ stamp_page(char const* infile, char const* stampfile, char const* outfile)
// 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 = ph.placeFormXObject( std::string content =
stamp_fo, name, ph.getTrimBox().getArrayAsRectangle(), m); ph.placeFormXObject(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

View File

@ -35,11 +35,9 @@ ParserCallbacks::contentSize(size_t size)
} }
void void
ParserCallbacks::handleObject( ParserCallbacks::handleObject(QPDFObjectHandle obj, 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 {
@ -67,8 +65,7 @@ main(int argc, char* argv[])
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();
} }

View File

@ -11,10 +11,8 @@ static char const* whoami = nullptr;
void void
usage() usage()
{ {
std::cerr << "Usage: " << whoami << " infile.pdf outfile.pdf value" std::cerr << "Usage: " << whoami << " infile.pdf outfile.pdf value" << std::endl
<< std::endl << "Set the value of all text fields to a specified value" << std::endl;
<< "Set the value of all text fields to a specified value"
<< std::endl;
exit(2); exit(2);
} }
@ -55,8 +53,7 @@ main(int argc, char* argv[])
for (auto& annot: afdh.getWidgetAnnotationsForPage(page)) { for (auto& annot: afdh.getWidgetAnnotationsForPage(page)) {
// 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);
afdh.getFieldForAnnotation(annot);
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
@ -79,8 +76,7 @@ main(int argc, char* argv[])
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

@ -22,13 +22,11 @@ process(char const* whoami, char const* infile, std::string outprefix)
{ {
QPDF inpdf; QPDF inpdf;
inpdf.processFile(infile); inpdf.processFile(infile);
std::vector<QPDFPageObjectHelper> pages = std::vector<QPDFPageObjectHelper> pages = QPDFPageDocumentHelper(inpdf).getAllPages();
QPDFPageDocumentHelper(inpdf).getAllPages();
int pageno_len = QIntC::to_int(std::to_string(pages.size()).length()); int pageno_len = QIntC::to_int(std::to_string(pages.size()).length());
int pageno = 0; int pageno = 0;
for (auto& page: pages) { for (auto& page: pages) {
std::string outfile = std::string outfile = outprefix + QUtil::int_to_string(++pageno, pageno_len) + ".pdf";
outprefix + QUtil::int_to_string(++pageno, pageno_len) + ".pdf";
QPDF outpdf; QPDF outpdf;
outpdf.emptyPDF(); outpdf.emptyPDF();
QPDFPageDocumentHelper(outpdf).addPage(page, false); QPDFPageDocumentHelper(outpdf).addPage(page, false);

View File

@ -83,8 +83,7 @@ main(int argc, char* argv[])
* saved data. You can use other qpdf logger functions to capture * saved data. You can use other qpdf logger functions to capture
* informational output, warnings, and errors. * informational output, warnings, and errors.
*/ */
qpdflogger_set_save( qpdflogger_set_save(l, qpdf_log_dest_custom, save_to_file, (void*)outfile, 0);
l, qpdf_log_dest_custom, save_to_file, (void*)outfile, 0);
qpdflogger_cleanup(&l); qpdflogger_cleanup(&l);
j = qpdfjob_init(); j = qpdfjob_init();
status = (qpdfjob_initialize_from_argv(j, j_argv) || qpdfjob_run(j)); status = (qpdfjob_initialize_from_argv(j, j_argv) || qpdfjob_run(j));

View File

@ -20,15 +20,10 @@ usageExit(std::string const& msg)
<< whoami << ": " << msg << std::endl << whoami << ": " << msg << std::endl
<< std::endl << std::endl
<< "For help:" << std::endl << "For help:" << std::endl
<< " " << whoami << " --help=usage usage information" << " " << whoami << " --help=usage usage information" << std::endl
<< std::endl << " " << whoami << " --help=topic help on a topic" << std::endl
<< " " << whoami << " --help=topic help on a topic" << " " << whoami << " --help=--option help on an option" << std::endl
<< std::endl << " " << whoami << " --help general help and a topic list" << std::endl
<< " " << whoami << " --help=--option help on an option"
<< std::endl
<< " " << whoami
<< " --help general help and a topic list"
<< std::endl
<< std::endl; << std::endl;
exit(QPDFJob::EXIT_ERROR); exit(QPDFJob::EXIT_ERROR);
} }

View File

@ -14,8 +14,7 @@ main(int argc, char* argv[])
auto whoami = QUtil::getWhoami(argv[0]); auto whoami = QUtil::getWhoami(argv[0]);
if (argc != 4) { if (argc != 4) {
std::cerr << "Usage: " << whoami << " file attachment-key outfile" std::cerr << "Usage: " << whoami << " file attachment-key outfile" << std::endl;
<< std::endl;
exit(2); exit(2);
} }

View File

@ -53,8 +53,8 @@ FuzzHelper::FuzzHelper(unsigned char const* data, size_t size) :
std::shared_ptr<QPDF> std::shared_ptr<QPDF>
FuzzHelper::getQpdf() FuzzHelper::getQpdf()
{ {
auto is = std::shared_ptr<InputSource>( auto is =
new BufferInputSource("fuzz input", &this->input_buffer)); std::shared_ptr<InputSource>(new BufferInputSource("fuzz input", &this->input_buffer));
auto qpdf = QPDF::create(); auto qpdf = QPDF::create();
qpdf->processInputSource(is); qpdf->processInputSource(is);
return qpdf; return qpdf;
@ -99,8 +99,7 @@ FuzzHelper::testWrite()
w = getWriter(q); w = getWriter(q);
w->setStaticID(true); w->setStaticID(true);
w->setLinearization(true); w->setLinearization(true);
w->setR6EncryptionParameters( w->setR6EncryptionParameters("u", "o", true, true, true, true, true, true, qpdf_r3p_full, true);
"u", "o", true, true, true, true, true, true, qpdf_r3p_full, true);
doWrite(w); doWrite(w);
q = getQpdf(); q = getQpdf();

View File

@ -11,8 +11,7 @@ main(int argc, char** argv)
std::shared_ptr<char> file_buf; std::shared_ptr<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);
LLVMFuzzerTestOneInput( LLVMFuzzerTestOneInput(reinterpret_cast<unsigned char*>(file_buf.get()), size);
reinterpret_cast<unsigned char*>(file_buf.get()), size);
std::cout << argv[i] << " successful" << std::endl; std::cout << argv[i] << " successful" << std::endl;
} }
return 0; return 0;

View File

@ -26,8 +26,7 @@ void
FuzzHelper::doChecks() FuzzHelper::doChecks()
{ {
Pl_Discard discard; Pl_Discard discard;
Pl_TIFFPredictor p( Pl_TIFFPredictor p("decoder", &discard, 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();
} }

View File

@ -31,11 +31,9 @@ class QPDF_DLL_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( BufferInputSource(std::string const& description, Buffer* buf, bool own_memory = false);
std::string const& description, Buffer* buf, bool own_memory = false);
QPDF_DLL QPDF_DLL
BufferInputSource( BufferInputSource(std::string const& description, 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

@ -230,9 +230,6 @@ 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_password_incorrect = 1 << 1 };
qpdf_es_encrypted = 1 << 0,
qpdf_es_password_incorrect = 1 << 1
};
#endif /* QPDFCONSTANTS_H */ #endif /* QPDFCONSTANTS_H */

View File

@ -69,17 +69,9 @@ 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( bool findFirst(char const* start_chars, qpdf_offset_t offset, size_t len, Finder& finder);
char const* start_chars,
qpdf_offset_t offset,
size_t len,
Finder& finder);
QPDF_DLL QPDF_DLL
bool findLast( bool findLast(char const* start_chars, qpdf_offset_t offset, size_t len, Finder& finder);
char const* start_chars,
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;
@ -144,8 +136,7 @@ InputSource::fastTell()
loadBuffer(); loadBuffer();
} else { } else {
auto curr = tell(); auto curr = tell();
if (curr < this->buf_start || if (curr < this->buf_start || curr >= (this->buf_start + this->buf_len)) {
curr >= (this->buf_start + this->buf_len)) {
loadBuffer(); loadBuffer();
} else { } else {
this->last_offset = curr; this->last_offset = curr;

View File

@ -104,19 +104,14 @@ class JSON
// the first item and always set it to false. // the first item and always set it to false.
QPDF_DLL QPDF_DLL
static void writeDictionaryItem( static void writeDictionaryItem(
Pipeline*, Pipeline*, bool& first, std::string const& key, JSON const& value, size_t depth = 0);
bool& first,
std::string const& key,
JSON const& value,
size_t depth = 0);
// Write just the key of a new dictionary item, useful if writing // Write just the key of a new dictionary item, useful if writing
// nested structures. Calls writeNext. // nested structures. Calls writeNext.
QPDF_DLL QPDF_DLL
static void writeDictionaryKey( static void
Pipeline* p, bool& first, std::string const& key, size_t depth = 0); writeDictionaryKey(Pipeline* p, bool& first, std::string const& key, size_t depth = 0);
QPDF_DLL QPDF_DLL
static void writeArrayItem( static void writeArrayItem(Pipeline*, bool& first, JSON const& element, size_t depth = 0);
Pipeline*, bool& first, JSON const& element, size_t depth = 0);
// If writing nested structures incrementally, call writeNext // If writing nested structures incrementally, call writeNext
// before opening a new array or container in the midst of an // before opening a new array or container in the midst of an
// existing one. The `first` you pass to writeNext should be the // existing one. The `first` you pass to writeNext should be the
@ -188,8 +183,7 @@ class JSON
QPDF_DLL QPDF_DLL
bool isNull() const; bool isNull() const;
QPDF_DLL QPDF_DLL
bool forEachDictItem( bool forEachDictItem(std::function<void(std::string const& key, JSON value)> fn) const;
std::function<void(std::string const& key, JSON value)> fn) const;
QPDF_DLL QPDF_DLL
bool forEachArrayItem(std::function<void(JSON value)> fn) const; bool forEachArrayItem(std::function<void(JSON value)> fn) const;
@ -239,8 +233,7 @@ class JSON
f_optional = 1 << 0, f_optional = 1 << 0,
}; };
QPDF_DLL QPDF_DLL
bool checkSchema( bool checkSchema(JSON schema, unsigned long flags, 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
@ -311,8 +304,7 @@ class JSON
// methods and decrementing on end methods. // methods and decrementing on end methods.
QPDF_DLL QPDF_DLL
virtual bool virtual bool dictionaryItem(std::string const& key, JSON const& value) = 0;
dictionaryItem(std::string const& key, JSON const& value) = 0;
QPDF_DLL QPDF_DLL
virtual bool arrayItem(JSON const& value) = 0; virtual bool arrayItem(JSON const& value) = 0;
}; };
@ -339,8 +331,7 @@ class JSON
private: private:
static std::string encode_string(std::string const& utf8); static std::string encode_string(std::string const& utf8);
static void static void writeClose(Pipeline* p, bool first, size_t depth, char const* delimeter);
writeClose(Pipeline* p, bool first, size_t depth, char const* delimeter);
enum value_type_e { enum value_type_e {
vt_none, vt_none,

View File

@ -54,15 +54,10 @@ class QPDF_DLL_CLASS Pl_Function: public Pipeline
// is thrown. // is thrown.
typedef int (*writer_c_t)(unsigned char const*, size_t, void*); typedef int (*writer_c_t)(unsigned char const*, size_t, void*);
QPDF_DLL QPDF_DLL
Pl_Function( Pl_Function(char const* identifier, Pipeline* next, writer_c_t fn, void* udata);
char const* identifier, Pipeline* next, writer_c_t fn, void* udata);
typedef int (*writer_c_char_t)(char const*, size_t, void*); typedef int (*writer_c_char_t)(char const*, size_t, void*);
QPDF_DLL QPDF_DLL
Pl_Function( Pl_Function(char const* identifier, Pipeline* next, writer_c_char_t fn, void* udata);
char const* identifier,
Pipeline* next,
writer_c_char_t fn,
void* udata);
QPDF_DLL QPDF_DLL
virtual ~Pl_Function(); virtual ~Pl_Function();

View File

@ -49,9 +49,7 @@ class QPDF_DLL_CLASS Pl_QPDFTokenizer: public Pipeline
// 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( Pl_QPDFTokenizer(
char const* identifier, char const* identifier, QPDFObjectHandle::TokenFilter* filter, Pipeline* next = nullptr);
QPDFObjectHandle::TokenFilter* filter,
Pipeline* next = nullptr);
QPDF_DLL QPDF_DLL
virtual ~Pl_QPDFTokenizer(); virtual ~Pl_QPDFTokenizer();
QPDF_DLL QPDF_DLL

View File

@ -78,9 +78,8 @@ namespace QIntC // QIntC = qpdf Integer Conversion
{ {
std::ostringstream msg; std::ostringstream msg;
msg.imbue(std::locale::classic()); msg.imbue(std::locale::classic());
msg << "integer out of range converting " << i << " from a " msg << "integer out of range converting " << i << " from a " << sizeof(From)
<< sizeof(From) << "-byte unsigned type to a " << sizeof(To) << "-byte unsigned type to a " << sizeof(To) << "-byte unsigned type";
<< "-byte unsigned type";
throw std::range_error(msg.str()); throw std::range_error(msg.str());
} }
}; };
@ -93,8 +92,7 @@ namespace QIntC // QIntC = qpdf Integer Conversion
convert(From const& i) 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())) {
error(i); error(i);
} }
return static_cast<To>(i); return static_cast<To>(i);
@ -105,9 +103,8 @@ namespace QIntC // QIntC = qpdf Integer Conversion
{ {
std::ostringstream msg; std::ostringstream msg;
msg.imbue(std::locale::classic()); msg.imbue(std::locale::classic());
msg << "integer out of range converting " << i << " from a " msg << "integer out of range converting " << i << " from a " << sizeof(From)
<< sizeof(From) << "-byte signed type to a " << sizeof(To) << "-byte signed type to a " << sizeof(To) << "-byte signed type";
<< "-byte signed type";
throw std::range_error(msg.str()); throw std::range_error(msg.str());
} }
}; };
@ -134,9 +131,8 @@ namespace QIntC // QIntC = qpdf Integer Conversion
{ {
std::ostringstream msg; std::ostringstream msg;
msg.imbue(std::locale::classic()); msg.imbue(std::locale::classic());
msg << "integer out of range converting " << i << " from a " msg << "integer out of range converting " << i << " from a " << sizeof(From)
<< sizeof(From) << "-byte signed type to a " << sizeof(To) << "-byte signed type to a " << sizeof(To) << "-byte unsigned type";
<< "-byte unsigned type";
throw std::range_error(msg.str()); throw std::range_error(msg.str());
} }
}; };
@ -150,8 +146,7 @@ namespace QIntC // QIntC = qpdf Integer Conversion
{ {
// 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) {
error(i); error(i);
} }
@ -163,9 +158,8 @@ namespace QIntC // QIntC = qpdf Integer Conversion
{ {
std::ostringstream msg; std::ostringstream msg;
msg.imbue(std::locale::classic()); msg.imbue(std::locale::classic());
msg << "integer out of range converting " << i << " from a " msg << "integer out of range converting " << i << " from a " << sizeof(From)
<< sizeof(From) << "-byte unsigned type to a " << sizeof(To) << "-byte unsigned type to a " << sizeof(To) << "-byte signed type";
<< "-byte signed type";
throw std::range_error(msg.str()); throw std::range_error(msg.str());
} }
}; };
@ -263,15 +257,12 @@ namespace QIntC // QIntC = qpdf Integer Conversion
if ((delta > 0) && ((std::numeric_limits<T>::max() - cur) < delta)) { if ((delta > 0) && ((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) && ((std::numeric_limits<T>::min() - cur) > delta)) {
(delta < 0) && ((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 << " would cause an integer underflow";
<< " would cause an integer underflow";
throw std::range_error(msg.str()); throw std::range_error(msg.str());
} }
} }
@ -296,12 +287,10 @@ namespace QIntC // QIntC = qpdf Integer Conversion
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) && ((std::numeric_limits<T>::max() + delta) < cur)) {
(delta < 0) && ((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 << " would cause an integer overflow";
<< " would cause an integer overflow";
throw std::range_error(msg.str()); throw std::range_error(msg.str());
} }
} }

View File

@ -93,10 +93,7 @@ class QPDF
// responsible for closing the file. // responsible for closing the file.
QPDF_DLL QPDF_DLL
void processFile( void processFile(
char const* description, char const* description, FILE* file, bool close_file, char const* password = nullptr);
FILE* file,
bool close_file,
char const* password = nullptr);
// 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
@ -104,17 +101,13 @@ class QPDF
// error message in place of the file name. // error message in place of the file name.
QPDF_DLL QPDF_DLL
void processMemoryFile( void processMemoryFile(
char const* description, char const* description, char const* buf, size_t length, char const* password = nullptr);
char const* buf,
size_t length,
char const* password = nullptr);
// 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( void processInputSource(std::shared_ptr<InputSource>, char const* password = nullptr);
std::shared_ptr<InputSource>, char const* password = nullptr);
// Create a PDF from an input source that contains JSON as written // Create a PDF from an input source that contains JSON as written
// by writeJSON (or qpdf --json-output, version 2 or higher). The // by writeJSON (or qpdf --json-output, version 2 or higher). The
@ -234,8 +227,7 @@ class QPDF
// QPDFStreamFilter classes. // QPDFStreamFilter classes.
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
@ -260,8 +252,7 @@ class QPDF
// configures a private logger, separating this object from the // configures a private logger, separating this object from the
// default logger, and calls setOutputStreams on that logger. See // default logger, and calls setOutputStreams on that logger. See
// QPDFLogger.hh for additional details. // QPDFLogger.hh for additional details.
[[deprecated( [[deprecated("configure logger from getLogger() or call setLogger()")]] QPDF_DLL void
"configure logger from getLogger() or call setLogger()")]] QPDF_DLL void
setOutputStreams(std::ostream* out_stream, std::ostream* err_stream); setOutputStreams(std::ostream* out_stream, std::ostream* err_stream);
// If true, ignore any cross-reference streams in a hybrid file // If true, ignore any cross-reference streams in a hybrid file
@ -481,8 +472,7 @@ class QPDF
// reserved object. After this call, reserved will be a reference // reserved object. After this call, reserved will be a reference
// to replacement. // to replacement.
QPDF_DLL QPDF_DLL
void void replaceReserved(QPDFObjectHandle reserved, QPDFObjectHandle replacement);
replaceReserved(QPDFObjectHandle reserved, 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
@ -657,8 +647,8 @@ class QPDF
int encryption_V, int encryption_V,
int encryption_R); int encryption_R);
QPDF_DLL QPDF_DLL
static std::string compute_encryption_key( static std::string
std::string const& password, EncryptionData const& data); compute_encryption_key(std::string const& password, EncryptionData const& data);
QPDF_DLL QPDF_DLL
static void compute_encryption_O_U( static void compute_encryption_O_U(
@ -843,8 +833,7 @@ class QPDF
QPDF_DLL QPDF_DLL
void addPage(QPDFObjectHandle newpage, bool first); void addPage(QPDFObjectHandle newpage, bool first);
QPDF_DLL QPDF_DLL
void void addPageAt(QPDFObjectHandle newpage, bool before, 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
@ -866,8 +855,7 @@ class QPDF
std::vector<QPDFObjectHandle>& part8, std::vector<QPDFObjectHandle>& part8,
std::vector<QPDFObjectHandle>& part9) std::vector<QPDFObjectHandle>& part9)
{ {
qpdf.getLinearizedParts( qpdf.getLinearizedParts(object_stream_data, part4, part6, part7, part8, part9);
object_stream_data, part4, part6, part7, part8, part9);
} }
static void static void
@ -880,8 +868,7 @@ class QPDF
int& S, int& S,
int& O) int& O)
{ {
return qpdf.generateHintStream( return qpdf.generateHintStream(xref, lengths, obj_renumber, hint_stream, S, O);
xref, lengths, obj_renumber, hint_stream, S, O);
} }
static void static void
@ -919,10 +906,7 @@ class QPDF
private: private:
static void static void
copyStreamData( copyStreamData(QPDF* qpdf, QPDFObjectHandle const& dest, QPDFObjectHandle const& src)
QPDF* qpdf,
QPDFObjectHandle const& dest,
QPDFObjectHandle const& src)
{ {
qpdf->copyStreamData(dest, src); qpdf->copyStreamData(dest, src);
} }
@ -968,13 +952,7 @@ class QPDF
bool will_retry) bool will_retry)
{ {
return qpdf->pipeStreamData( return qpdf->pipeStreamData(
og, og, offset, length, dict, pipeline, suppress_warnings, will_retry);
offset,
length,
dict,
pipeline,
suppress_warnings,
will_retry);
} }
}; };
@ -1096,16 +1074,13 @@ class QPDF
Pipeline* pipeline, Pipeline* pipeline,
bool suppress_warnings, bool suppress_warnings,
bool will_retry) override; bool will_retry) override;
void registerForeignStream( void registerForeignStream(QPDFObjGen const& local_og, QPDFObjectHandle foreign_stream);
QPDFObjGen const& local_og, QPDFObjectHandle foreign_stream); void registerForeignStream(QPDFObjGen const& local_og, std::shared_ptr<ForeignStreamData>);
void registerForeignStream(
QPDFObjGen const& local_og, std::shared_ptr<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::shared_ptr<ForeignStreamData>> std::map<QPDFObjGen, std::shared_ptr<ForeignStreamData>> foreign_stream_data;
foreign_stream_data;
}; };
class StringDecrypter: public QPDFObjectHandle::StringDecrypter class StringDecrypter: public QPDFObjectHandle::StringDecrypter
@ -1148,29 +1123,21 @@ class QPDF
void read_xref(qpdf_offset_t offset); void read_xref(qpdf_offset_t offset);
bool resolveXRefTable(); bool resolveXRefTable();
void reconstruct_xref(QPDFExc& e); void reconstruct_xref(QPDFExc& e);
bool bool parse_xrefFirst(std::string const& line, 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, qpdf_offset_t& f1, int& f2, char& type);
bool parse_xrefEntry(
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 qpdf_offset_t processXRefStream(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, bool overwrite = false);
void insertXrefEntry( void setLastObjectDescription(std::string const& description, QPDFObjGen const& og);
int obj, int f0, qpdf_offset_t f1, int f2, bool overwrite = false);
void setLastObjectDescription(
std::string const& description, QPDFObjGen const& og);
QPDFObjectHandle readObject( QPDFObjectHandle readObject(
std::shared_ptr<InputSource>, std::shared_ptr<InputSource>,
std::string const& description, std::string const& description,
QPDFObjGen const& og, QPDFObjGen const& og,
bool in_object_stream); bool in_object_stream);
size_t recoverStreamLength( size_t recoverStreamLength(
std::shared_ptr<InputSource> input, std::shared_ptr<InputSource> input, QPDFObjGen const& og, qpdf_offset_t stream_offset);
QPDFObjGen const& og, QPDFTokenizer::Token readToken(std::shared_ptr<InputSource>, size_t max_len = 0);
qpdf_offset_t stream_offset);
QPDFTokenizer::Token
readToken(std::shared_ptr<InputSource>, size_t max_len = 0);
QPDFObjectHandle readObjectAtOffset( QPDFObjectHandle readObjectAtOffset(
bool attempt_recovery, bool attempt_recovery,
@ -1185,10 +1152,8 @@ class QPDF
QPDFObjectHandle reserveObjectIfNotExists(QPDFObjGen const& og); QPDFObjectHandle reserveObjectIfNotExists(QPDFObjGen const& og);
QPDFObjectHandle reserveStream(QPDFObjGen const& og); QPDFObjectHandle reserveStream(QPDFObjGen const& og);
QPDFObjGen nextObjGen(); QPDFObjGen nextObjGen();
QPDFObjectHandle QPDFObjectHandle newIndirect(QPDFObjGen const&, std::shared_ptr<QPDFObject> const&);
newIndirect(QPDFObjGen const&, std::shared_ptr<QPDFObject> const&); QPDFObjectHandle makeIndirectFromQPDFObject(std::shared_ptr<QPDFObject> const& obj);
QPDFObjectHandle
makeIndirectFromQPDFObject(std::shared_ptr<QPDFObject> const& obj);
bool isCached(QPDFObjGen const& og); bool isCached(QPDFObjGen const& og);
bool isUnresolved(QPDFObjGen const& og); bool isUnresolved(QPDFObjGen const& og);
void updateCache( void updateCache(
@ -1205,10 +1170,7 @@ class QPDF
std::shared_ptr<InputSource> const& input, std::shared_ptr<InputSource> const& input,
qpdf_offset_t offset, qpdf_offset_t offset,
std::string const& message); std::string const& message);
QPDFExc damagedPDF( QPDFExc damagedPDF(std::string const& object, qpdf_offset_t offset, std::string const& message);
std::string const& object,
qpdf_offset_t offset,
std::string const& message);
QPDFExc damagedPDF(std::string const& object, std::string const& message); QPDFExc damagedPDF(std::string const& object, std::string const& message);
QPDFExc damagedPDF(qpdf_offset_t offset, std::string const& message); QPDFExc damagedPDF(qpdf_offset_t offset, std::string const& message);
QPDFExc damagedPDF(std::string const& message); QPDFExc damagedPDF(std::string const& message);
@ -1223,10 +1185,7 @@ class QPDF
bool suppress_warnings, bool suppress_warnings,
bool will_retry); bool will_retry);
bool pipeForeignStreamData( bool pipeForeignStreamData(
std::shared_ptr<ForeignStreamData>, std::shared_ptr<ForeignStreamData>, Pipeline*, bool suppress_warnings, bool will_retry);
Pipeline*,
bool suppress_warnings,
bool will_retry);
static bool pipeStreamData( static bool pipeStreamData(
std::shared_ptr<QPDF::EncryptionParameters> encp, std::shared_ptr<QPDF::EncryptionParameters> encp,
std::shared_ptr<InputSource> file, std::shared_ptr<InputSource> file,
@ -1269,31 +1228,24 @@ class QPDF
// methods to support page handling // methods to support page handling
void getAllPagesInternal( void getAllPagesInternal(
QPDFObjectHandle cur_pages, QPDFObjectHandle cur_pages, QPDFObjGen::set& visited, QPDFObjGen::set& seen);
QPDFObjGen::set& visited,
QPDFObjGen::set& seen);
void insertPage(QPDFObjectHandle newpage, int pos); void insertPage(QPDFObjectHandle newpage, int pos);
void flattenPagesTree(); void flattenPagesTree();
void insertPageobjToPage( void insertPageobjToPage(QPDFObjectHandle const& obj, int pos, 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 static encryption_method_e
interpretCF(std::shared_ptr<EncryptionParameters> encp, QPDFObjectHandle); interpretCF(std::shared_ptr<EncryptionParameters> encp, QPDFObjectHandle);
void initializeEncryption(); void initializeEncryption();
static std::string getKeyForObject( static std::string
std::shared_ptr<EncryptionParameters> encp, getKeyForObject(std::shared_ptr<EncryptionParameters> encp, QPDFObjGen const& og, bool use_aes);
QPDFObjGen const& og,
bool use_aes);
void decryptString(std::string&, QPDFObjGen const& og); void decryptString(std::string&, QPDFObjGen const& og);
static std::string compute_encryption_key_from_password( static std::string
std::string const& password, EncryptionData const& data); compute_encryption_key_from_password(std::string const& password, EncryptionData const& data);
static std::string
recover_encryption_key_with_password(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);
static std::string recover_encryption_key_with_password(
std::string const& password,
EncryptionData const& data,
bool& perms_valid);
static void decryptStream( static void decryptStream(
std::shared_ptr<EncryptionParameters> encp, std::shared_ptr<EncryptionParameters> encp,
std::shared_ptr<InputSource> file, std::shared_ptr<InputSource> file,
@ -1304,12 +1256,10 @@ class QPDF
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 void reserveObjects(QPDFObjectHandle foreign, ObjCopier& obj_copier, bool top);
reserveObjects(QPDFObjectHandle foreign, ObjCopier& obj_copier, bool top); QPDFObjectHandle
QPDFObjectHandle replaceForeignIndirectObjects( replaceForeignIndirectObjects(QPDFObjectHandle foreign, ObjCopier& obj_copier, bool top);
QPDFObjectHandle foreign, ObjCopier& obj_copier, bool top); void copyStreamData(QPDFObjectHandle dest_stream, QPDFObjectHandle src_stream);
void
copyStreamData(QPDFObjectHandle dest_stream, QPDFObjectHandle src_stream);
// Linearization Hint table structures. // Linearization Hint table structures.
// Naming conventions: // Naming conventions:
@ -1538,14 +1488,7 @@ class QPDF
class ObjUser class ObjUser
{ {
public: public:
enum user_e { enum user_e { ou_bad, ou_page, ou_thumb, ou_trailer_key, ou_root_key, ou_root };
ou_bad,
ou_page,
ou_thumb,
ou_trailer_key,
ou_root_key,
ou_root
};
// type is set to ou_bad // type is set to ou_bad
ObjUser(); ObjUser();
@ -1598,29 +1541,25 @@ class QPDF
bool checkLinearizationInternal(); bool checkLinearizationInternal();
void dumpLinearizationDataInternal(); void dumpLinearizationDataInternal();
void linearizationWarning(std::string_view); void linearizationWarning(std::string_view);
QPDFObjectHandle QPDFObjectHandle readHintStream(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&);
qpdf_offset_t maxEnd(ObjUser const& ou); qpdf_offset_t maxEnd(ObjUser const& ou);
qpdf_offset_t getLinearizationOffset(QPDFObjGen const&); qpdf_offset_t getLinearizationOffset(QPDFObjGen const&);
QPDFObjectHandle getUncompressedObject( QPDFObjectHandle
QPDFObjectHandle&, std::map<int, int> const& object_stream_data); getUncompressedObject(QPDFObjectHandle&, std::map<int, int> const& object_stream_data);
int lengthNextN(int first_object, int n); int lengthNextN(int first_object, int n);
void checkHPageOffset( void
std::vector<QPDFObjectHandle> const& pages, checkHPageOffset(std::vector<QPDFObjectHandle> const& pages, std::map<int, int>& idx_to_obj);
std::map<int, int>& idx_to_obj); void
void checkHSharedObject( checkHSharedObject(std::vector<QPDFObjectHandle> const& pages, std::map<int, int>& idx_to_obj);
std::vector<QPDFObjectHandle> const& pages,
std::map<int, int>& idx_to_obj);
void checkHOutlines(); void checkHOutlines();
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);
void void calculateLinearizationData(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,
@ -1648,8 +1587,7 @@ class QPDF
// Methods to support optimization // Methods to support optimization
void void pushInheritedAttributesToPage(bool allow_changes, 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>>&,
@ -1681,11 +1619,7 @@ class QPDF
qpdf_json_stream_data_e, qpdf_json_stream_data_e,
std::string const& file_prefix); std::string const& file_prefix);
void writeJSONObject( void writeJSONObject(
int version, int version, Pipeline* p, bool& first, std::string const& key, QPDFObjectHandle&);
Pipeline* p,
bool& first,
std::string const& key,
QPDFObjectHandle&);
// Type conversion helper methods // Type conversion helper methods
template <typename T> template <typename T>

View File

@ -148,18 +148,15 @@ class QPDFAcroFormDocumentHelper: public QPDFDocumentHelper
// underlying object will typically be the same as the underlying // underlying object will typically be the same as the underlying
// 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
@ -251,10 +248,7 @@ class QPDFAcroFormDocumentHelper: public QPDFDocumentHelper
private: private:
void analyze(); void analyze();
void traverseField( void traverseField(
QPDFObjectHandle field, QPDFObjectHandle field, QPDFObjectHandle parent, int depth, QPDFObjGen::set& visited);
QPDFObjectHandle parent,
int depth,
QPDFObjGen::set& visited);
QPDFObjectHandle getOrCreateAcroForm(); QPDFObjectHandle getOrCreateAcroForm();
void adjustInheritedFields( void adjustInheritedFields(
QPDFObjectHandle obj, QPDFObjectHandle obj,
@ -264,11 +258,9 @@ class QPDFAcroFormDocumentHelper: public QPDFDocumentHelper
int from_default_q); int from_default_q);
void adjustDefaultAppearances( void adjustDefaultAppearances(
QPDFObjectHandle obj, QPDFObjectHandle obj,
std::map<std::string, std::map<std::string, std::string>> const& std::map<std::string, 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::string>> dr_map);
std::map<std::string, std::map<std::string, std::string>> dr_map);
class Members class Members
{ {
@ -283,8 +275,7 @@ class QPDFAcroFormDocumentHelper: public QPDFDocumentHelper
Members(Members const&) = delete; Members(Members const&) = delete;
bool cache_valid; bool cache_valid;
std::map<QPDFObjGen, std::vector<QPDFAnnotationObjectHelper>> std::map<QPDFObjGen, 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

@ -76,8 +76,7 @@ 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( QPDFObjectHandle getAppearanceStream(std::string const& which, 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

View File

@ -77,10 +77,8 @@ 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( virtual void
unsigned char const* in_data, RC4_process(unsigned char const* in_data, size_t len, unsigned char* out_data = nullptr) = 0;
size_t len,
unsigned char* out_data = nullptr) = 0;
QPDF_DLL QPDF_DLL
virtual void RC4_finalize() = 0; virtual void RC4_finalize() = 0;
@ -93,8 +91,7 @@ class QPDF_DLL_CLASS QPDFCryptoImpl
bool cbc_mode, bool cbc_mode,
unsigned char* cbc_block) = 0; unsigned char* cbc_block) = 0;
QPDF_DLL QPDF_DLL
virtual void virtual void rijndael_process(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

@ -78,8 +78,7 @@ class QPDFCryptoProvider
static QPDFCryptoProvider& getInstance(); static QPDFCryptoProvider& getInstance();
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);

View File

@ -75,11 +75,9 @@ class QPDFEFStreamObjectHelper: public QPDFObjectHelper
// checksum and size are computed automatically and stored. Other // checksum and size are computed automatically and stored. Other
// parameters may be supplied using setters defined below. // parameters may be supplied using setters defined below.
QPDF_DLL QPDF_DLL
static QPDFEFStreamObjectHelper static QPDFEFStreamObjectHelper createEFStream(QPDF& qpdf, std::shared_ptr<Buffer> data);
createEFStream(QPDF& qpdf, std::shared_ptr<Buffer> data);
QPDF_DLL QPDF_DLL
static QPDFEFStreamObjectHelper static QPDFEFStreamObjectHelper createEFStream(QPDF& qpdf, std::string const& data);
createEFStream(QPDF& qpdf, std::string const& data);
// The provider function must write the data to the given // The provider function must write the data to the given
// pipeline. The function may be called multiple times by the qpdf // pipeline. The function may be called multiple times by the qpdf
// library. You can pass QUtil::file_provider(filename) as the // library. You can pass QUtil::file_provider(filename) as the

View File

@ -48,19 +48,16 @@ class QPDFEmbeddedFileDocumentHelper: public QPDFDocumentHelper
bool hasEmbeddedFiles() const; bool hasEmbeddedFiles() const;
QPDF_DLL QPDF_DLL
std::map<std::string, std::shared_ptr<QPDFFileSpecObjectHelper>> std::map<std::string, 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.
QPDF_DLL QPDF_DLL
std::shared_ptr<QPDFFileSpecObjectHelper> std::shared_ptr<QPDFFileSpecObjectHelper> getEmbeddedFile(std::string const& name);
getEmbeddedFile(std::string const& name);
// Add or replace an attachment // Add or replace an attachment
QPDF_DLL QPDF_DLL
void replaceEmbeddedFile( void replaceEmbeddedFile(std::string const& name, QPDFFileSpecObjectHelper const&);
std::string const& name, QPDFFileSpecObjectHelper const&);
// Remove an embedded file if present. Return value is true if the // Remove an embedded file if present. Return value is true if the
// file was present and was removed. This method not only removes // file was present and was removed. This method not only removes

View File

@ -77,16 +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 QPDFFileSpecObjectHelper createFileSpec( static QPDFFileSpecObjectHelper
QPDF& qpdf, std::string const& filename, std::string const& fullpath); createFileSpec(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 QPDFFileSpecObjectHelper createFileSpec( static QPDFFileSpecObjectHelper
QPDF& qpdf, std::string const& filename, QPDFEFStreamObjectHelper); createFileSpec(QPDF& qpdf, std::string const& filename, QPDFEFStreamObjectHelper);
QPDF_DLL QPDF_DLL
QPDFFileSpecObjectHelper& setDescription(std::string const&); QPDFFileSpecObjectHelper& setDescription(std::string const&);
@ -96,8 +96,8 @@ class QPDFFileSpecObjectHelper: public QPDFObjectHelper
// QPDFObjectHandle literally, preserving whatever encoding it // QPDFObjectHandle literally, preserving whatever encoding it
// might happen to have. // might happen to have.
QPDF_DLL QPDF_DLL
QPDFFileSpecObjectHelper& setFilename( QPDFFileSpecObjectHelper&
std::string const& unicode_name, std::string const& compat_name = ""); setFilename(std::string const& unicode_name, std::string const& compat_name = "");
private: private:
class Members class Members

View File

@ -183,8 +183,7 @@ class QPDFFormFieldObjectHelper: public QPDFObjectHelper
// of a field, use QPDFAcroFormDocumentHelper::setFormFieldName // of a field, use QPDFAcroFormDocumentHelper::setFormFieldName
// instead. // instead.
QPDF_DLL QPDF_DLL
void void setFieldAttribute(std::string const& key, 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),
@ -218,8 +217,7 @@ class QPDFFormFieldObjectHelper: public QPDFObjectHelper
void setRadioButtonValue(QPDFObjectHandle name); void setRadioButtonValue(QPDFObjectHandle name);
void setCheckBoxValue(bool value); void setCheckBoxValue(bool value);
void generateTextAppearance(QPDFAnnotationObjectHelper&); void generateTextAppearance(QPDFAnnotationObjectHelper&);
QPDFObjectHandle getFontFromResource( QPDFObjectHandle getFontFromResource(QPDFObjectHandle resources, std::string const& font_name);
QPDFObjectHandle resources, std::string const& font_name);
class Members class Members
{ {

View File

@ -83,8 +83,7 @@ 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( void initializeFromArgv(char const* const argv[], 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
@ -132,8 +131,7 @@ class QPDFJob
// configures a private logger, separating this object from the // configures a private logger, separating this object from the
// default logger, and calls setOutputStreams on that logger. See // default logger, and calls setOutputStreams on that logger. See
// QPDFLogger.hh for additional details. // QPDFLogger.hh for additional details.
[[deprecated( [[deprecated("configure logger from getLogger() or call setLogger()")]] QPDF_DLL void
"configure logger from getLogger() or call setLogger()")]] QPDF_DLL void
setOutputStreams(std::ostream* out_stream, std::ostream* err_stream); setOutputStreams(std::ostream* out_stream, std::ostream* err_stream);
// You can register a custom progress reporter to be called by // You can register a custom progress reporter to be called by
@ -187,10 +185,7 @@ class QPDFJob
struct PageSpec struct PageSpec
{ {
PageSpec( PageSpec(std::string const& filename, char const* password, std::string const& range);
std::string const& filename,
char const* password,
std::string const& range);
std::string filename; std::string filename;
std::shared_ptr<char> password; std::shared_ptr<char> password;
@ -284,9 +279,7 @@ class QPDFJob
Config* endPages(); Config* endPages();
QPDF_DLL QPDF_DLL
PagesConfig* pageSpec( PagesConfig* pageSpec(
std::string const& filename, std::string const& filename, std::string const& range, 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>
@ -366,10 +359,8 @@ class QPDFJob
QPDF_DLL QPDF_DLL
std::shared_ptr<UOConfig> underlay(); std::shared_ptr<UOConfig> underlay();
QPDF_DLL QPDF_DLL
std::shared_ptr<EncConfig> encrypt( std::shared_ptr<EncConfig>
int keylen, encrypt(int keylen, std::string const& user_password, std::string const& owner_password);
std::string const& user_password,
std::string const& owner_password);
#include <qpdf/auto_job_c_main.hh> #include <qpdf/auto_job_c_main.hh>
@ -438,8 +429,7 @@ class QPDFJob
// If in verbose mode, call the given function, passing in the // If in verbose mode, call the given function, passing in the
// output stream and message prefix. // output stream and message prefix.
QPDF_DLL QPDF_DLL
void void doIfVerbose(std::function<void(Pipeline&, std::string const& prefix)> fn);
doIfVerbose(std::function<void(Pipeline&, std::string const& prefix)> fn);
// Provide a string that is the help information ("schema" for the // Provide a string that is the help information ("schema" for the
// qpdf-specific JSON object) for the specified version of JSON // qpdf-specific JSON object) for the specified version of JSON
@ -447,16 +437,14 @@ class QPDFJob
QPDF_DLL QPDF_DLL
static std::string json_out_schema(int version); static std::string json_out_schema(int version);
[[deprecated("use json_out_schema(version)")]] static std::string QPDF_DLL [[deprecated("use json_out_schema(version)")]] static std::string QPDF_DLL json_out_schema_v1();
json_out_schema_v1();
// Provide a string that is the help information for specified // Provide a string that is the help information for specified
// version of JSON format for QPDFJob. // version of JSON format for QPDFJob.
QPDF_DLL QPDF_DLL
static std::string job_json_schema(int version); static std::string job_json_schema(int version);
[[deprecated("use job_json_schema(version)")]] static std::string QPDF_DLL [[deprecated("use job_json_schema(version)")]] static std::string QPDF_DLL job_json_schema_v1();
job_json_schema_v1();
private: private:
struct RotationSpec struct RotationSpec
@ -497,10 +485,8 @@ class QPDFJob
// Helper functions // Helper functions
static void usage(std::string const& msg); static void usage(std::string const& msg);
static JSON static JSON json_schema(int json_version, std::set<std::string>* keys = nullptr);
json_schema(int json_version, std::set<std::string>* keys = nullptr); static void parse_object_id(std::string const& objspec, bool& trailer, int& obj, int& gen);
static void parse_object_id(
std::string const& objspec, bool& trailer, int& obj, int& gen);
void parseRotationParameter(std::string const&); void parseRotationParameter(std::string const&);
std::vector<int> parseNumrange(char const* range, int max); std::vector<int> parseNumrange(char const* range, int max);
@ -533,12 +519,10 @@ class QPDFJob
// Transformations // Transformations
void setQPDFOptions(QPDF& pdf); void setQPDFOptions(QPDF& pdf);
void void handlePageSpecs(QPDF& pdf, std::vector<std::unique_ptr<QPDF>>& page_heap);
handlePageSpecs(QPDF& pdf, std::vector<std::unique_ptr<QPDF>>& page_heap);
bool shouldRemoveUnreferencedResources(QPDF& pdf); bool shouldRemoveUnreferencedResources(QPDF& pdf);
void handleRotations(QPDF& pdf); void handleRotations(QPDF& pdf);
void void getUOPagenos(UnderOverlay& uo, 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);
std::string doUnderOverlayForPage( std::string doUnderOverlayForPage(
QPDF& pdf, QPDF& pdf,
@ -573,8 +557,7 @@ class QPDFJob
// JSON // JSON
void doJSON(QPDF& pdf, Pipeline*); void doJSON(QPDF& pdf, Pipeline*);
QPDFObjGen::set getWantedJSONObjects(); QPDFObjGen::set getWantedJSONObjects();
void doJSONObject( void doJSONObject(Pipeline* p, bool& first, std::string const& key, QPDFObjectHandle&);
Pipeline* p, bool& first, std::string const& key, QPDFObjectHandle&);
void doJSONObjects(Pipeline* p, bool& first, QPDF& pdf); void doJSONObjects(Pipeline* p, bool& first, QPDF& pdf);
void doJSONObjectinfo(Pipeline* p, bool& first, QPDF& pdf); void doJSONObjectinfo(Pipeline* p, bool& first, QPDF& pdf);
void doJSONPages(Pipeline* p, bool& first, QPDF& pdf); void doJSONPages(Pipeline* p, bool& first, QPDF& pdf);

View File

@ -153,8 +153,7 @@ class QPDFLogger
private: private:
QPDFLogger(); QPDFLogger();
std::shared_ptr<Pipeline> std::shared_ptr<Pipeline> throwIfNull(std::shared_ptr<Pipeline>, bool null_okay);
throwIfNull(std::shared_ptr<Pipeline>, bool null_okay);
class Members class Members
{ {

View File

@ -79,8 +79,7 @@ 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 QPDFObjectHandle::Rectangle transformRectangle(QPDFObjectHandle::Rectangle r) const;
transformRectangle(QPDFObjectHandle::Rectangle r) const;
// operator== tests for exact equality, not considering deltas for // operator== tests for exact equality, not considering deltas for
// floating point. // floating point.

View File

@ -156,8 +156,7 @@ class QPDF_DLL_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 iterator find(std::string const& key, 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

@ -45,8 +45,7 @@ class QPDF_DLL_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( QPDFNumberTreeObjectHelper(QPDFObjectHandle, QPDF&, bool auto_repair = true);
QPDFObjectHandle, QPDF&, bool auto_repair = true);
QPDF_DLL QPDF_DLL
virtual ~QPDFNumberTreeObjectHelper(); virtual ~QPDFNumberTreeObjectHelper();
@ -82,8 +81,7 @@ class QPDF_DLL_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( bool findObjectAtOrBelow(numtree_number idx, QPDFObjectHandle& oh, numtree_number& offset);
numtree_number idx, QPDFObjectHandle& oh, numtree_number& offset);
class QPDF_DLL_PRIVATE iterator class QPDF_DLL_PRIVATE iterator
{ {

View File

@ -128,22 +128,13 @@ 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 virtual void provideStreamData(QPDFObjGen const& og, Pipeline* pipeline);
provideStreamData(QPDFObjGen const& og, Pipeline* pipeline);
QPDF_DLL QPDF_DLL
virtual bool provideStreamData( virtual bool provideStreamData(
QPDFObjGen const& og, QPDFObjGen const& og, Pipeline* pipeline, bool suppress_warnings, bool will_retry);
Pipeline* pipeline, QPDF_DLL virtual void provideStreamData(int objid, int generation, Pipeline* pipeline);
bool suppress_warnings,
bool will_retry);
QPDF_DLL virtual void
provideStreamData(int objid, int generation, Pipeline* pipeline);
QPDF_DLL virtual bool provideStreamData( QPDF_DLL virtual bool provideStreamData(
int objid, int objid, int generation, Pipeline* pipeline, bool suppress_warnings, bool will_retry);
int generation,
Pipeline* pipeline,
bool suppress_warnings,
bool will_retry);
QPDF_DLL QPDF_DLL
bool supportsRetry(); bool supportsRetry();
@ -246,8 +237,7 @@ class QPDFObjectHandle
QPDF_DLL QPDF_DLL
virtual void handleObject(QPDFObjectHandle); virtual void handleObject(QPDFObjectHandle);
QPDF_DLL QPDF_DLL
virtual void virtual void handleObject(QPDFObjectHandle, size_t offset, size_t length);
handleObject(QPDFObjectHandle, size_t offset, size_t length);
virtual void handleEOF() = 0; virtual void handleEOF() = 0;
@ -408,14 +398,12 @@ 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( bool isDictionaryOfType(std::string const& type, 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 bool isStreamOfType(std::string const& type, std::string const& subtype = "");
isStreamOfType(std::string const& type, std::string const& subtype = "");
// Public factory methods // Public factory methods
@ -433,9 +421,8 @@ 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( static QPDFObjectHandle
std::string const& object_str, parse(std::string const& object_str, std::string const& object_description = "");
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
@ -447,10 +434,8 @@ 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( static QPDFObjectHandle
QPDF* context, parse(QPDF* context, std::string const& object_str, 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
@ -480,8 +465,7 @@ 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( static void parseContentStream(QPDFObjectHandle stream_or_array, 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
@ -500,10 +484,8 @@ 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( void
Pipeline* p, pipeContentStreams(Pipeline* p, std::string const& description, std::string& all_description);
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
@ -554,8 +536,8 @@ class QPDFObjectHandle
QPDF_DLL QPDF_DLL
static QPDFObjectHandle newReal(std::string const& value); static QPDFObjectHandle newReal(std::string const& value);
QPDF_DLL QPDF_DLL
static QPDFObjectHandle newReal( static QPDFObjectHandle
double value, int decimal_places = 0, bool trim_trailing_zeroes = true); newReal(double value, int decimal_places = 0, bool trim_trailing_zeroes = true);
// 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
@ -591,8 +573,7 @@ class QPDFObjectHandle
QPDF_DLL QPDF_DLL
static QPDFObjectHandle newArray(); static QPDFObjectHandle newArray();
QPDF_DLL QPDF_DLL
static QPDFObjectHandle static QPDFObjectHandle newArray(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
@ -602,8 +583,7 @@ class QPDFObjectHandle
QPDF_DLL QPDF_DLL
static QPDFObjectHandle newDictionary(); static QPDFObjectHandle newDictionary();
QPDF_DLL QPDF_DLL
static QPDFObjectHandle static QPDFObjectHandle newDictionary(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.
@ -686,8 +666,7 @@ class QPDFObjectHandle
// else. To add objects from another qpdf, use copyForeignObject // else. To add objects from another qpdf, use copyForeignObject
// instead. // instead.
QPDF_DLL QPDF_DLL
void setObjectDescription( void setObjectDescription(QPDF* owning_qpdf, std::string const& object_description);
QPDF* owning_qpdf, std::string const& object_description);
QPDF_DLL QPDF_DLL
bool hasObjectDescription(); bool hasObjectDescription();
@ -964,8 +943,7 @@ class QPDFObjectHandle
QPDF_DLL QPDF_DLL
void mergeResources( void mergeResources(
QPDFObjectHandle other, QPDFObjectHandle other,
std::map<std::string, std::map<std::string, std::string>>* conflicts = std::map<std::string, std::map<std::string, std::string>>* conflicts = nullptr);
nullptr);
// Get all resource names from a resource dictionary. If this // Get all resource names from a resource dictionary. If this
// object is a dictionary, this method returns a set of all the // object is a dictionary, this method returns a set of all the
@ -1118,13 +1096,11 @@ class QPDFObjectHandle
void replaceKey(std::string const& key, QPDFObjectHandle const& value); void replaceKey(std::string const& key, QPDFObjectHandle const& value);
// Replace value of key and return the value. // Replace value of key and return the value.
QPDF_DLL QPDF_DLL
QPDFObjectHandle QPDFObjectHandle replaceKeyAndGetNew(std::string const& key, QPDFObjectHandle const& value);
replaceKeyAndGetNew(std::string const& key, QPDFObjectHandle const& value);
// Replace value of key and return the old value, or null if the // Replace value of key and return the old value, or null if the
// key was previously not present. // key was previously not present.
QPDF_DLL QPDF_DLL
QPDFObjectHandle QPDFObjectHandle replaceKeyAndGetOld(std::string const& key, QPDFObjectHandle const& value);
replaceKeyAndGetOld(std::string const& key, QPDFObjectHandle const& value);
// Remove key, doing nothing if key does not exist. // Remove key, doing nothing if key does not exist.
QPDF_DLL QPDF_DLL
void removeKey(std::string const& key); void removeKey(std::string const& key);
@ -1167,8 +1143,7 @@ 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
std::shared_ptr<Buffer> std::shared_ptr<Buffer> getStreamData(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
@ -1347,8 +1322,7 @@ class QPDFObjectHandle
// 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*, bool suppress_warnings, bool will_retry)> std::function<bool(Pipeline*, bool suppress_warnings, bool will_retry)> provider,
provider,
QPDFObjectHandle const& filter, QPDFObjectHandle const& filter,
QPDFObjectHandle const& decode_parms); QPDFObjectHandle const& decode_parms);
@ -1615,15 +1589,14 @@ class QPDFObjectHandle
void makeDirect(QPDFObjGen::set& visited, bool stop_at_streams); void makeDirect(QPDFObjGen::set& visited, bool stop_at_streams);
void disconnect(); void disconnect();
void setParsedOffset(qpdf_offset_t offset); void setParsedOffset(qpdf_offset_t offset);
void parseContentStream_internal( void parseContentStream_internal(std::string const& description, ParserCallbacks* callbacks);
std::string const& description, ParserCallbacks* callbacks);
static void parseContentStream_data( static void parseContentStream_data(
std::shared_ptr<Buffer>, std::shared_ptr<Buffer>,
std::string const& description, std::string const& description,
ParserCallbacks* callbacks, ParserCallbacks* callbacks,
QPDF* context); QPDF* context);
std::vector<QPDFObjectHandle> arrayOrStreamToStreamArray( std::vector<QPDFObjectHandle>
std::string const& description, std::string& all_description); arrayOrStreamToStreamArray(std::string const& description, std::string& all_description);
static void warn(QPDF*, QPDFExc const&); static void warn(QPDF*, QPDFExc const&);
void checkOwnership(QPDFObjectHandle const&) const; void checkOwnership(QPDFObjectHandle const&) const;

View File

@ -104,10 +104,7 @@ 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( void addPageAt(QPDFPageObjectHelper newpage, bool before, QPDFPageObjectHelper refpage);
QPDFPageObjectHelper newpage,
bool before,
QPDFPageObjectHelper refpage);
// Remove page from the pdf. // Remove page from the pdf.
QPDF_DLL QPDF_DLL
@ -125,8 +122,7 @@ class QPDFPageDocumentHelper: public QPDFDocumentHelper
// comments there in QPDFAnnotationObjectHelper.hh for meanings of // comments there in QPDFAnnotationObjectHelper.hh for meanings of
// those flags. // those flags.
QPDF_DLL QPDF_DLL
void flattenAnnotations( void flattenAnnotations(int required_flags = 0, int forbidden_flags = an_invisible | an_hidden);
int required_flags = 0, int forbidden_flags = an_invisible | an_hidden);
private: private:
void flattenAnnotationsForPage( void flattenAnnotationsForPage(

View File

@ -170,26 +170,22 @@ class QPDFPageObjectHelper: public QPDFObjectHelper
// Return the effective CropBox. If not defined, fall back to // Return the effective CropBox. If not defined, fall back to
// MediaBox // MediaBox
QPDF_DLL QPDF_DLL
QPDFObjectHandle QPDFObjectHandle getCropBox(bool copy_if_shared = false, bool copy_if_fallback = false);
getCropBox(bool copy_if_shared = false, bool copy_if_fallback = false);
// Return the effective BleedBox. If not defined, fall back to // Return the effective BleedBox. If not defined, fall back to
// CropBox. // CropBox.
QPDF_DLL QPDF_DLL
QPDFObjectHandle QPDFObjectHandle getBleedBox(bool copy_if_shared = false, bool copy_if_fallback = false);
getBleedBox(bool copy_if_shared = false, bool copy_if_fallback = false);
// Return the effective TrimBox. If not defined, fall back to // Return the effective TrimBox. If not defined, fall back to
// CropBox. // CropBox.
QPDF_DLL QPDF_DLL
QPDFObjectHandle QPDFObjectHandle getTrimBox(bool copy_if_shared = false, bool copy_if_fallback = false);
getTrimBox(bool copy_if_shared = false, bool copy_if_fallback = false);
// Return the effective ArtBox. If not defined, fall back to // Return the effective ArtBox. If not defined, fall back to
// CropBox. // CropBox.
QPDF_DLL QPDF_DLL
QPDFObjectHandle QPDFObjectHandle getArtBox(bool copy_if_shared = false, bool copy_if_fallback = false);
getArtBox(bool copy_if_shared = false, bool copy_if_fallback = 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
@ -203,26 +199,20 @@ class QPDFPageObjectHelper: public QPDFObjectHelper
void forEachXObject( void forEachXObject(
bool recursive, bool recursive,
std::function<void( std::function<void(
QPDFObjectHandle& obj, QPDFObjectHandle& obj, QPDFObjectHandle& xobj_dict, std::string const& key)> action,
QPDFObjectHandle& xobj_dict,
std::string const& key)> action,
std::function<bool(QPDFObjectHandle)> selector = nullptr); 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( std::function<void(
QPDFObjectHandle& obj, QPDFObjectHandle& obj, QPDFObjectHandle& xobj_dict, 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( std::function<void(
QPDFObjectHandle& obj, QPDFObjectHandle& obj, QPDFObjectHandle& xobj_dict, 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
@ -258,8 +248,7 @@ 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> std::vector<QPDFAnnotationObjectHelper> getAnnotations(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
@ -319,13 +308,11 @@ 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( void filterContents(QPDFObjectHandle::TokenFilter* filter, Pipeline* next = nullptr);
QPDFObjectHandle::TokenFilter* filter, Pipeline* next = nullptr);
// Old name -- calls filterContents() // Old name -- calls filterContents()
QPDF_DLL QPDF_DLL
void filterPageContents( void filterPageContents(QPDFObjectHandle::TokenFilter* filter, Pipeline* next = nullptr);
QPDFObjectHandle::TokenFilter* filter, Pipeline* next = nullptr);
// 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
@ -341,8 +328,7 @@ class QPDFPageObjectHelper: public QPDFObjectHelper
// The token filter is applied to the page's contents as a single // The token filter is applied to the page's contents as a single
// stream. Also works on form XObjects. // stream. Also works on form XObjects.
QPDF_DLL QPDF_DLL
void addContentTokenFilter( void addContentTokenFilter(std::shared_ptr<QPDFObjectHandle::TokenFilter> token_filter);
std::shared_ptr<QPDFObjectHandle::TokenFilter> token_filter);
// A page's resources dictionary maps names to objects elsewhere // A page's resources dictionary maps names to objects elsewhere
// in the file. This method walks through a page's contents and // in the file. This method walks through a page's contents and
@ -500,8 +486,8 @@ class QPDFPageObjectHelper: public QPDFObjectHelper
bool copy_if_shared, bool copy_if_shared,
std::function<QPDFObjectHandle()> get_fallback, std::function<QPDFObjectHandle()> get_fallback,
bool copy_if_fallback); bool copy_if_fallback);
static bool removeUnreferencedResourcesHelper( static bool
QPDFPageObjectHelper ph, std::set<std::string>& unresolved); removeUnreferencedResourcesHelper(QPDFPageObjectHelper ph, std::set<std::string>& unresolved);
class Members class Members
{ {

View File

@ -48,8 +48,7 @@ class QPDF_DLL_CLASS QPDFSystemError: public std::runtime_error
private: private:
QPDF_DLL_PRIVATE QPDF_DLL_PRIVATE
static std::string static std::string createWhat(std::string const& description, 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

@ -104,8 +104,7 @@ class QPDFTokenizer
{ {
// Ignore fields other than type and value // Ignore fields other than type and value
return ( return (
(this->type != tt_bad) && (this->type == rhs.type) && (this->type != tt_bad) && (this->type == rhs.type) && (this->value == rhs.value));
(this->value == rhs.value));
} }
bool bool
isInteger() const isInteger() const
@ -216,8 +215,7 @@ class QPDFTokenizer
// beginning of the token. Returns false if the token is bad // beginning of the token. Returns false if the token is bad
// or if scanning produced an error message for any reason. // or if scanning produced an error message for any reason.
bool nextToken( bool nextToken(InputSource& input, std::string const& context, size_t max_len = 0);
InputSource& input, std::string const& context, size_t max_len = 0);
// The following methods are only valid after nextToken has been called // The following methods are only valid after nextToken has been called
// and until another QPDFTokenizer method is called. They allow the results // and until another QPDFTokenizer method is called. They allow the results
@ -317,8 +315,7 @@ QPDFTokenizer::getType() const noexcept
inline std::string const& inline std::string const&
QPDFTokenizer::getValue() const noexcept QPDFTokenizer::getValue() const noexcept
{ {
return (this->type == tt_name || this->type == tt_string) ? this->val return (this->type == tt_name || this->type == tt_string) ? this->val : this->raw_val;
: this->raw_val;
} }
inline std::string const& inline std::string const&
QPDFTokenizer::getRawValue() const noexcept QPDFTokenizer::getRawValue() const noexcept

View File

@ -561,16 +561,11 @@ class QPDFWriter
void writePad(size_t nspaces); void writePad(size_t nspaces);
void assignCompressedObjectNumbers(QPDFObjGen const& og); void assignCompressedObjectNumbers(QPDFObjGen const& og);
void enqueueObject(QPDFObjectHandle object); void enqueueObject(QPDFObjectHandle object);
void writeObjectStreamOffsets( void writeObjectStreamOffsets(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( void writeTrailer(
trailer_e which, trailer_e which, int size, bool xref_stream, qpdf_offset_t prev, int linearization_pass);
int size,
bool xref_stream,
qpdf_offset_t prev,
int linearization_pass);
bool willFilterStream( bool willFilterStream(
QPDFObjectHandle stream, QPDFObjectHandle stream,
bool& compress_stream, bool& compress_stream,
@ -601,8 +596,7 @@ class QPDFWriter
bool allow_modify_other, bool allow_modify_other,
qpdf_r3_print_e print, qpdf_r3_print_e print,
qpdf_r3_modify_e modify); qpdf_r3_modify_e modify);
void void disableIncompatibleEncryption(int major, int minor, int extension_level);
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(
@ -640,8 +634,7 @@ class QPDFWriter
void doWriteSetup(); void doWriteSetup();
void writeHeader(); void writeHeader();
void writeHintStream(int hint_id); void writeHintStream(int hint_id);
qpdf_offset_t qpdf_offset_t writeXRefTable(trailer_e which, int first, int last, int size);
writeXRefTable(trailer_e which, int first, int last, int size);
qpdf_offset_t writeXRefTable( qpdf_offset_t writeXRefTable(
trailer_e which, trailer_e which,
int first, int first,
@ -693,8 +686,7 @@ class QPDFWriter
void pushMD5Pipeline(PipelinePopper&); void pushMD5Pipeline(PipelinePopper&);
void computeDeterministicIDData(); void computeDeterministicIDData();
void discardGeneration( void discardGeneration(std::map<QPDFObjGen, int> const& in, std::map<int, int>& out);
std::map<QPDFObjGen, int> const& in, std::map<int, int>& out);
class Members class Members
{ {

View File

@ -49,11 +49,9 @@ 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 std::string uint_to_string_base(unsigned long long, int base, int length = 0);
uint_to_string_base(unsigned long long, int base, int length = 0);
QPDF_DLL QPDF_DLL
std::string double_to_string( std::string double_to_string(double, int decimal_places = 0, bool trim_trailing_zeroes = true);
double, int decimal_places = 0, bool trim_trailing_zeroes = true);
// These string to number methods throw std::runtime_error on // These string to number methods throw std::runtime_error on
// underflow/overflow. // underflow/overflow.
@ -257,14 +255,7 @@ 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( QPDFTime(int year, int month, int day, int hour, 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),
@ -331,8 +322,7 @@ namespace QUtil
// to pass a value of pos that is greater than or equal to the // to pass a value of pos that is greater than or equal to the
// length of the string. // length of the string.
QPDF_DLL QPDF_DLL
unsigned long get_next_utf8_codepoint( unsigned long get_next_utf8_codepoint(std::string const& utf8_val, size_t& pos, bool& error);
std::string const& utf8_val, size_t& pos, bool& error);
// Test whether this is a UTF-16 string. This is indicated by // Test whether this is a UTF-16 string. This is indicated by
// first two bytes being 0xFE 0xFF (big-endian) or 0xFF 0xFE // first two bytes being 0xFE 0xFF (big-endian) or 0xFF 0xFE
@ -360,30 +350,23 @@ namespace QUtil
QPDF_DLL QPDF_DLL
std::string utf8_to_ascii(std::string const& utf8, char unknown_char = '?'); std::string utf8_to_ascii(std::string const& utf8, char unknown_char = '?');
QPDF_DLL QPDF_DLL
std::string std::string utf8_to_win_ansi(std::string const& utf8, char unknown_char = '?');
utf8_to_win_ansi(std::string const& utf8, char unknown_char = '?');
QPDF_DLL QPDF_DLL
std::string std::string utf8_to_mac_roman(std::string const& utf8, char unknown_char = '?');
utf8_to_mac_roman(std::string const& utf8, char unknown_char = '?');
QPDF_DLL QPDF_DLL
std::string std::string utf8_to_pdf_doc(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
// be substituted with the unknown character. // be substituted with the unknown character.
QPDF_DLL QPDF_DLL
bool utf8_to_ascii( bool utf8_to_ascii(std::string const& utf8, std::string& ascii, char unknown_char = '?');
std::string const& utf8, std::string& ascii, char unknown_char = '?');
QPDF_DLL QPDF_DLL
bool utf8_to_win_ansi( bool utf8_to_win_ansi(std::string const& utf8, std::string& win, char unknown_char = '?');
std::string const& utf8, std::string& win, char unknown_char = '?');
QPDF_DLL QPDF_DLL
bool utf8_to_mac_roman( bool utf8_to_mac_roman(std::string const& utf8, std::string& mac, char unknown_char = '?');
std::string const& utf8, std::string& mac, char unknown_char = '?');
QPDF_DLL QPDF_DLL
bool utf8_to_pdf_doc( bool utf8_to_pdf_doc(std::string const& utf8, std::string& pdfdoc, char unknown_char = '?');
std::string const& utf8, std::string& pdfdoc, char unknown_char = '?');
// Convert a UTF-16 encoded string to UTF-8. Unrepresentable code // Convert a UTF-16 encoded string to UTF-8. Unrepresentable code
// points are converted to U+FFFD. // points are converted to U+FFFD.
@ -412,10 +395,7 @@ namespace QUtil
// 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( void analyze_encoding(
std::string const& str, std::string const& str, bool& has_8bit_chars, bool& is_valid_utf8, bool& is_utf16);
bool& has_8bit_chars,
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:
@ -472,14 +452,11 @@ 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> std::list<std::string> read_lines_from_file(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> std::list<std::string> read_lines_from_file(std::istream&, bool preserve_eol = false);
read_lines_from_file(std::istream&, bool preserve_eol = false);
QPDF_DLL QPDF_DLL
std::list<std::string> std::list<std::string> read_lines_from_file(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,
@ -487,8 +464,7 @@ namespace QUtil
bool preserve_eol = false); bool preserve_eol = false);
QPDF_DLL QPDF_DLL
void read_file_into_memory( void read_file_into_memory(char const* filename, std::shared_ptr<char>& file_buf, size_t& size);
char const* filename, std::shared_ptr<char>& file_buf, size_t& size);
QPDF_DLL QPDF_DLL
std::string read_file_into_string(char const* filename); std::string read_file_into_string(char const* filename);
@ -532,8 +508,7 @@ namespace QUtil
// invoked, convert all UTF-16 encoded strings to UTF-8, and call // invoked, convert all UTF-16 encoded strings to UTF-8, and call
// another main. // another main.
QPDF_DLL QPDF_DLL
int call_main_from_wmain( int call_main_from_wmain(int argc, wchar_t* argv[], std::function<int(int, char*[])> realmain);
int argc, wchar_t* argv[], std::function<int(int, char*[])> realmain);
QPDF_DLL QPDF_DLL
int call_main_from_wmain( int call_main_from_wmain(
int argc, int argc,
@ -561,8 +536,7 @@ QUtil::is_hex_digit(char ch)
inline bool inline bool
QUtil::is_space(char ch) QUtil::is_space(char ch)
{ {
return ch == ' ' || ch == '\n' || ch == '\r' || ch == '\t' || ch == '\f' || return ch == ' ' || ch == '\n' || ch == '\r' || ch == '\t' || ch == '\f' || ch == '\v';
ch == '\v';
} }
inline bool inline bool
@ -603,8 +577,7 @@ inline std::string
QUtil::hex_encode_char(char c) QUtil::hex_encode_char(char c)
{ {
static auto constexpr hexchars = "0123456789abcdef"; static auto constexpr hexchars = "0123456789abcdef";
return { return {'#', hexchars[static_cast<unsigned char>(c) >> 4], hexchars[c & 0x0f]};
'#', hexchars[static_cast<unsigned char>(c) >> 4], hexchars[c & 0x0f]};
} }
inline constexpr char inline constexpr char
@ -612,8 +585,7 @@ QUtil::hex_decode_char(char digit) noexcept
{ {
return digit <= '9' && digit >= '0' return digit <= '9' && digit >= '0'
? char(digit - '0') ? char(digit - '0')
: (digit >= 'a' ? char(digit - 'a' + 10) : (digit >= 'a' ? char(digit - 'a' + 10) : (digit >= 'A' ? char(digit - 'A' + 10) : '\20'));
: (digit >= 'A' ? char(digit - 'A' + 10) : '\20'));
} }
#endif // QUTIL_HH #endif // QUTIL_HH

View File

@ -326,8 +326,7 @@ extern "C" {
*/ */
QPDF_DLL QPDF_DLL
QPDF_ERROR_CODE QPDF_ERROR_CODE
qpdf_create_from_json_data( qpdf_create_from_json_data(qpdf_data qpdf, char const* buffer, unsigned long long size);
qpdf_data qpdf, char const* buffer, unsigned long long size);
/* JSON UPDATE FUNCTIONS */ /* JSON UPDATE FUNCTIONS */
@ -341,8 +340,7 @@ extern "C" {
qpdf_update_from_json_file(qpdf_data qpdf, char const* filename); qpdf_update_from_json_file(qpdf_data qpdf, char const* filename);
QPDF_DLL QPDF_DLL
QPDF_ERROR_CODE QPDF_ERROR_CODE
qpdf_update_from_json_data( qpdf_update_from_json_data(qpdf_data qpdf, char const* buffer, unsigned long long size);
qpdf_data qpdf, char const* buffer, unsigned long long size);
/* READ FUNCTIONS */ /* READ FUNCTIONS */
@ -492,23 +490,19 @@ 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 void qpdf_set_object_stream_mode(qpdf_data qpdf, 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 void qpdf_set_stream_data_mode(qpdf_data qpdf, 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 QPDF_DLL
void qpdf_set_decode_level( void qpdf_set_decode_level(qpdf_data qpdf, enum qpdf_stream_decode_level_e level);
qpdf_data qpdf, enum qpdf_stream_decode_level_e level);
QPDF_DLL QPDF_DLL
void void qpdf_set_preserve_unreferenced_objects(qpdf_data qpdf, QPDF_BOOL value);
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);
@ -625,8 +619,8 @@ extern "C" {
void qpdf_force_pdf_version(qpdf_data qpdf, char const* version); void qpdf_force_pdf_version(qpdf_data qpdf, char const* version);
QPDF_DLL QPDF_DLL
void qpdf_force_pdf_version_and_extension( void
qpdf_data qpdf, char const* version, int extension_level); qpdf_force_pdf_version_and_extension(qpdf_data qpdf, char const* version, int extension_level);
/* During write, your report_progress function will be called with /* During write, your report_progress function will be called with
* a value between 0 and 100 representing the approximate write * a value between 0 and 100 representing the approximate write
@ -640,9 +634,7 @@ extern "C" {
*/ */
QPDF_DLL QPDF_DLL
void qpdf_register_progress_reporter( void qpdf_register_progress_reporter(
qpdf_data qpdf, qpdf_data qpdf, void (*report_progress)(int percent, void* data), void* data);
void (*report_progress)(int percent, void* data),
void* data);
/* Do actual write operation. */ /* Do actual write operation. */
QPDF_DLL QPDF_DLL
@ -733,8 +725,7 @@ 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 void qpdf_replace_object(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
@ -811,8 +802,7 @@ extern "C" {
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
QPDF_BOOL qpdf_oh_get_value_as_ulonglong( QPDF_BOOL qpdf_oh_get_value_as_ulonglong(qpdf_data qpdf, qpdf_oh oh, unsigned long long* value);
qpdf_data qpdf, qpdf_oh oh, unsigned long long* value);
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
@ -822,8 +812,8 @@ extern "C" {
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);
QPDF_DLL QPDF_DLL
QPDF_BOOL qpdf_oh_get_value_as_real( QPDF_BOOL
qpdf_data qpdf, qpdf_oh oh, char const** value, size_t* length); qpdf_oh_get_value_as_real(qpdf_data qpdf, qpdf_oh oh, char const** value, size_t* length);
QPDF_DLL QPDF_DLL
QPDF_BOOL qpdf_oh_is_number(qpdf_data qpdf, qpdf_oh oh); QPDF_BOOL qpdf_oh_is_number(qpdf_data qpdf, qpdf_oh oh);
@ -836,8 +826,8 @@ extern "C" {
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);
QPDF_DLL QPDF_DLL
QPDF_BOOL qpdf_oh_get_value_as_name( QPDF_BOOL
qpdf_data qpdf, qpdf_oh oh, char const** value, size_t* length); qpdf_oh_get_value_as_name(qpdf_data qpdf, qpdf_oh oh, char const** value, size_t* length);
/* Return the length of the last string returned. This enables you /* Return the length of the last string returned. This enables you
* to retrieve the entire string for cases in which a char* * to retrieve the entire string for cases in which a char*
@ -858,19 +848,17 @@ extern "C" {
QPDF_DLL QPDF_DLL
char const* qpdf_oh_get_string_value(qpdf_data qpdf, qpdf_oh oh); char const* qpdf_oh_get_string_value(qpdf_data qpdf, qpdf_oh oh);
QPDF_DLL QPDF_DLL
QPDF_BOOL qpdf_oh_get_value_as_string( QPDF_BOOL
qpdf_data qpdf, qpdf_oh oh, char const** value, size_t* length); qpdf_oh_get_value_as_string(qpdf_data qpdf, qpdf_oh oh, char const** value, size_t* length);
QPDF_DLL QPDF_DLL
char const* qpdf_oh_get_utf8_value(qpdf_data qpdf, qpdf_oh oh); char const* qpdf_oh_get_utf8_value(qpdf_data qpdf, qpdf_oh oh);
QPDF_DLL QPDF_DLL
QPDF_BOOL qpdf_oh_get_value_as_utf8( QPDF_BOOL
qpdf_data qpdf, qpdf_oh oh, char const** value, size_t* length); qpdf_oh_get_value_as_utf8(qpdf_data qpdf, qpdf_oh oh, char const** value, size_t* length);
QPDF_DLL QPDF_DLL
char const* char const* qpdf_oh_get_binary_string_value(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* char const* qpdf_oh_get_binary_utf8_value(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);
@ -906,8 +894,7 @@ 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 qpdf_oh_get_key_if_dict(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_BOOL
@ -924,8 +911,7 @@ 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_oh qpdf_oh_new_real_from_double(qpdf_data qpdf, 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
@ -936,11 +922,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 qpdf_oh_new_binary_string(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
qpdf_oh qpdf_oh_new_array(qpdf_data qpdf); qpdf_oh qpdf_oh_new_array(qpdf_data qpdf);
QPDF_DLL QPDF_DLL
@ -959,8 +943,7 @@ 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 void qpdf_oh_set_array_item(qpdf_data qpdf, qpdf_oh oh, 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
@ -969,13 +952,11 @@ 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( void qpdf_oh_replace_key(qpdf_data qpdf, qpdf_oh oh, 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( void qpdf_oh_replace_or_remove_key(qpdf_data qpdf, qpdf_oh oh, 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);
@ -1005,8 +986,7 @@ extern "C" {
* while `foreign_oh` belongs to `other_qpdf`. * while `foreign_oh` belongs to `other_qpdf`.
*/ */
QPDF_DLL QPDF_DLL
qpdf_oh qpdf_oh_copy_foreign_object( qpdf_oh qpdf_oh_copy_foreign_object(qpdf_data qpdf, qpdf_data other_qpdf, qpdf_oh foreign_oh);
qpdf_data qpdf, qpdf_data other_qpdf, qpdf_oh foreign_oh);
/* STREAM FUNCTIONS */ /* STREAM FUNCTIONS */
@ -1105,19 +1085,12 @@ extern "C" {
/* addPage() */ /* addPage() */
QPDF_DLL QPDF_DLL
QPDF_ERROR_CODE qpdf_add_page( QPDF_ERROR_CODE
qpdf_data qpdf, qpdf_add_page(qpdf_data qpdf, qpdf_data newpage_qpdf, qpdf_oh newpage, QPDF_BOOL first);
qpdf_data newpage_qpdf,
qpdf_oh newpage,
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_BOOL before, qpdf_oh refpage);
qpdf_data newpage_qpdf,
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);

View File

@ -111,8 +111,7 @@ extern "C" {
* is invalid to call any other functions this job handle. * is invalid to call any other functions this job handle.
*/ */
QPDF_DLL QPDF_DLL
int int qpdfjob_initialize_from_argv(qpdfjob_handle j, char const* const argv[]);
qpdfjob_initialize_from_argv(qpdfjob_handle j, char const* const argv[]);
#ifndef QPDF_NO_WCHAR_T #ifndef QPDF_NO_WCHAR_T
/* This function is the same as qpdfjob_initialize_from_argv /* This function is the same as qpdfjob_initialize_from_argv
@ -120,8 +119,7 @@ extern "C" {
* suitable for calling from a Windows wmain function. * suitable for calling from a Windows wmain function.
*/ */
QPDF_DLL QPDF_DLL
int qpdfjob_initialize_from_wide_argv( int qpdfjob_initialize_from_wide_argv(qpdfjob_handle j, wchar_t const* const argv[]);
qpdfjob_handle j, wchar_t const* const argv[]);
#endif /* QPDF_NO_WCHAR_T */ #endif /* QPDF_NO_WCHAR_T */
/* This function wraps QPDFJob::initializeFromJson. The return /* This function wraps QPDFJob::initializeFromJson. The return
@ -167,9 +165,7 @@ extern "C" {
*/ */
QPDF_DLL QPDF_DLL
void qpdfjob_register_progress_reporter( void qpdfjob_register_progress_reporter(
qpdfjob_handle j, qpdfjob_handle j, void (*report_progress)(int percent, void* data), void* data);
void (*report_progress)(int percent, void* data),
void* data);
#ifdef __cplusplus #ifdef __cplusplus
} }

View File

@ -76,22 +76,13 @@ extern "C" {
QPDF_DLL QPDF_DLL
void qpdflogger_set_info( void qpdflogger_set_info(
qpdflogger_handle l, qpdflogger_handle l, enum qpdf_log_dest_e dest, qpdf_log_fn_t fn, void* udata);
enum qpdf_log_dest_e dest,
qpdf_log_fn_t fn,
void* udata);
QPDF_DLL QPDF_DLL
void qpdflogger_set_warn( void qpdflogger_set_warn(
qpdflogger_handle l, qpdflogger_handle l, enum qpdf_log_dest_e dest, qpdf_log_fn_t fn, void* udata);
enum qpdf_log_dest_e dest,
qpdf_log_fn_t fn,
void* udata);
QPDF_DLL QPDF_DLL
void qpdflogger_set_error( void qpdflogger_set_error(
qpdflogger_handle l, qpdflogger_handle l, enum qpdf_log_dest_e dest, qpdf_log_fn_t fn, void* udata);
enum qpdf_log_dest_e dest,
qpdf_log_fn_t fn,
void* udata);
/* A non-zero value for only_if_not_set means that the save /* A non-zero value for only_if_not_set means that the save
* pipeline will only be changed if it is not already set. * pipeline will only be changed if it is not already set.
@ -104,8 +95,7 @@ extern "C" {
void* udata, void* udata,
int only_if_not_set); int only_if_not_set);
QPDF_DLL QPDF_DLL
void qpdflogger_save_to_standard_output( void qpdflogger_save_to_standard_output(qpdflogger_handle l, int only_if_not_set);
qpdflogger_handle l, int only_if_not_set);
/* For testing */ /* For testing */
QPDF_DLL QPDF_DLL

View File

@ -27,11 +27,9 @@ AES_PDF_native::AES_PDF_native(
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(this->rk.get(), this->key.get(), keybits);
rijndaelSetupEncrypt(this->rk.get(), this->key.get(), keybits);
} else { } else {
this->nrounds = this->nrounds = rijndaelSetupDecrypt(this->rk.get(), this->key.get(), keybits);
rijndaelSetupDecrypt(this->rk.get(), this->key.get(), keybits);
} }
} }
@ -46,8 +44,7 @@ AES_PDF_native::update(unsigned char* in_data, unsigned char* out_data)
} }
rijndaelEncrypt(this->rk.get(), this->nrounds, in_data, out_data); rijndaelEncrypt(this->rk.get(), this->nrounds, in_data, out_data);
if (this->cbc_mode) { if (this->cbc_mode) {
memcpy( memcpy(this->cbc_block, out_data, QPDFCryptoImpl::rijndael_buf_size);
this->cbc_block, out_data, QPDFCryptoImpl::rijndael_buf_size);
} }
} else { } else {
rijndaelDecrypt(this->rk.get(), this->nrounds, in_data, out_data); rijndaelDecrypt(this->rk.get(), this->nrounds, in_data, out_data);

View File

@ -33,8 +33,7 @@ BitStream::getBits(size_t nbits)
long long long long
BitStream::getBitsSigned(size_t nbits) BitStream::getBitsSigned(size_t nbits)
{ {
unsigned long long bits = unsigned long long bits = read_bits(this->p, this->bit_offset, 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));
@ -49,8 +48,7 @@ BitStream::getBitsInt(size_t nbits)
{ {
return static_cast<int>( return static_cast<int>(
// line-break // line-break
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
@ -59,8 +57,7 @@ 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");
} }
bit_offset = 7; bit_offset = 7;
++p; ++p;

View File

@ -5,8 +5,7 @@
#include <cstring> #include <cstring>
#include <sstream> #include <sstream>
BufferInputSource::BufferInputSource( BufferInputSource::BufferInputSource(std::string const& description, Buffer* buf, bool own_memory) :
std::string const& description, Buffer* buf, bool own_memory) :
own_memory(own_memory), own_memory(own_memory),
description(description), description(description),
buf(buf), buf(buf),
@ -15,8 +14,7 @@ BufferInputSource::BufferInputSource(
{ {
} }
BufferInputSource::BufferInputSource( BufferInputSource::BufferInputSource(std::string const& description, std::string const& contents) :
std::string const& description, std::string const& contents) :
own_memory(true), own_memory(true),
description(description), description(description),
buf(new Buffer(contents.length())), buf(new Buffer(contents.length())),
@ -100,14 +98,12 @@ BufferInputSource::seek(qpdf_offset_t offset, int whence)
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->cur_offset < 0) { if (this->cur_offset < 0) {
throw std::runtime_error( throw std::runtime_error(this->description + ": seek before beginning of buffer");
this->description + ": seek before beginning of buffer");
} }
} }

View File

@ -44,13 +44,11 @@ ContentNormalizer::handleToken(QPDFTokenizer::Token const& token)
// 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( writeToken(QPDFTokenizer::Token(QPDFTokenizer::tt_string, token.getValue()));
QPDFTokenizer::Token(QPDFTokenizer::tt_string, token.getValue()));
break; break;
case QPDFTokenizer::tt_name: case QPDFTokenizer::tt_name:
writeToken( writeToken(QPDFTokenizer::Token(QPDFTokenizer::tt_name, token.getValue()));
QPDFTokenizer::Token(QPDFTokenizer::tt_name, token.getValue()));
break; break;
default: default:
@ -59,10 +57,8 @@ ContentNormalizer::handleToken(QPDFTokenizer::Token const& token)
} }
value = token.getRawValue(); value = token.getRawValue();
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('\n') != std::string::npos))) {
((value.find('\r') != std::string::npos) ||
(value.find('\n') != std::string::npos))) {
write("\n"); write("\n");
} }
} }

View File

@ -18,8 +18,7 @@ FileInputSource::FileInputSource(char const* filename) :
{ {
} }
FileInputSource::FileInputSource( FileInputSource::FileInputSource(char const* description, FILE* filep, bool close_file) :
char const* description, FILE* filep, bool close_file) :
close_file(close_file), close_file(close_file),
filename(description), filename(description),
file(filep) file(filep)
@ -104,8 +103,8 @@ FileInputSource::seek(qpdf_offset_t offset, int whence)
{ {
if (QUtil::seek(this->file, offset, whence) == -1) { if (QUtil::seek(this->file, offset, whence) == -1) {
QUtil::throw_system_error( QUtil::throw_system_error(
std::string("seek to ") + this->filename + ", offset " + std::string("seek to ") + this->filename + ", offset " + std::to_string(offset) + " (" +
std::to_string(offset) + " (" + std::to_string(whence) + ")"); std::to_string(whence) + ")");
} }
} }

View File

@ -43,8 +43,7 @@ InputSource::readLine(size_t max_line_length)
} }
bool bool
InputSource::findFirst( InputSource::findFirst(char const* start_chars, qpdf_offset_t offset, size_t len, Finder& finder)
char const* start_chars, qpdf_offset_t offset, size_t len, 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
@ -64,9 +63,8 @@ InputSource::findFirst(
// 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");
} }
char* p = nullptr; char* p = nullptr;
@ -86,13 +84,10 @@ InputSource::findFirst(
// 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 == nullptr) || if ((p == nullptr) || ((p + strlen(start_chars)) > (buf + bytes_read))) {
((p + strlen(start_chars)) > (buf + bytes_read))) {
if (p) { if (p) {
QTC::TC( QTC::TC(
"libtests", "libtests", "InputSource read next block", ((p == buf + bytes_read) ? 0 : 1));
"InputSource read next block",
((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);
@ -102,10 +97,7 @@ InputSource::findFirst(
// 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", bytes_read == 0 ? 0 : 1);
"libtests",
"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));
@ -115,18 +107,14 @@ InputSource::findFirst(
// Search for the first character. // Search for the first character.
if ((p = static_cast<char*>( if ((p = static_cast<char*>(
// line-break // line-break
memchr( memchr(p, start_chars[0], bytes_read - QIntC::to_size(p - buf)))) != nullptr) {
p,
start_chars[0],
bytes_read - QIntC::to_size(p - buf)))) != nullptr) {
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");
@ -151,14 +139,10 @@ InputSource::findFirst(
if (finder.check()) { if (finder.check()) {
return true; return true;
} else { } else {
QTC::TC( QTC::TC("libtests", "InputSource start_chars matched but not check");
"libtests",
"InputSource start_chars matched but not check");
} }
} else { } else {
QTC::TC( QTC::TC("libtests", "InputSource first char matched but not string");
"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.
@ -172,8 +156,7 @@ InputSource::findFirst(
} }
bool bool
InputSource::findLast( InputSource::findLast(char const* start_chars, qpdf_offset_t offset, size_t len, Finder& finder)
char const* start_chars, qpdf_offset_t offset, size_t len, Finder& finder)
{ {
bool found = false; bool found = false;
qpdf_offset_t after_found_offset = 0; qpdf_offset_t after_found_offset = 0;

View File

@ -24,8 +24,7 @@ InsecureRandomDataProvider::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.
auto seed = auto seed = static_cast<unsigned int>(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

View File

@ -73,8 +73,7 @@ JSON::writeArrayClose(Pipeline* p, bool first, size_t depth)
} }
void void
JSON::writeDictionaryKey( JSON::writeDictionaryKey(Pipeline* p, bool& first, std::string const& key, size_t depth)
Pipeline* p, bool& first, std::string const& key, size_t depth)
{ {
writeNext(p, first, depth); writeNext(p, first, depth);
*p << std::string("\"") + key + "\": "; *p << std::string("\"") + key + "\": ";
@ -82,19 +81,14 @@ JSON::writeDictionaryKey(
void void
JSON::writeDictionaryItem( JSON::writeDictionaryItem(
Pipeline* p, Pipeline* p, bool& first, std::string const& key, JSON const& value, size_t depth)
bool& first,
std::string const& key,
JSON const& value,
size_t depth)
{ {
writeDictionaryKey(p, first, key, depth); writeDictionaryKey(p, first, key, depth);
value.write(p, depth); value.write(p, depth);
} }
void void
JSON::writeArrayItem( JSON::writeArrayItem(Pipeline* p, bool& first, JSON const& element, size_t depth)
Pipeline* p, bool& first, JSON const& element, size_t depth)
{ {
writeNext(p, first, depth); writeNext(p, first, depth);
element.write(p, depth); element.write(p, depth);
@ -283,11 +277,9 @@ JSON
JSON::addDictionaryMember(std::string const& key, JSON const& val) JSON::addDictionaryMember(std::string const& key, JSON const& val)
{ {
if (auto* obj = dynamic_cast<JSON_dictionary*>(m->value.get())) { if (auto* obj = dynamic_cast<JSON_dictionary*>(m->value.get())) {
return obj->members[encode_string(key)] = return obj->members[encode_string(key)] = val.m->value ? val : makeNull();
val.m->value ? val : makeNull();
} else { } else {
throw std::runtime_error( throw std::runtime_error("JSON::addDictionaryMember called on non-dictionary");
"JSON::addDictionaryMember called on non-dictionary");
} }
} }
@ -296,8 +288,7 @@ JSON::checkDictionaryKeySeen(std::string const& key)
{ {
auto* obj = dynamic_cast<JSON_dictionary*>(m->value.get()); auto* obj = dynamic_cast<JSON_dictionary*>(m->value.get());
if (nullptr == obj) { if (nullptr == obj) {
throw std::logic_error( throw std::logic_error("JSON::checkDictionaryKey called on non-dictionary");
"JSON::checkDictionaryKey called on non-dictionary");
} }
if (obj->parsed_keys.count(key)) { if (obj->parsed_keys.count(key)) {
return true; return true;
@ -421,8 +412,7 @@ JSON::isNull() const
} }
bool bool
JSON::forEachDictItem( JSON::forEachDictItem(std::function<void(std::string const& key, JSON value)> fn) const
std::function<void(std::string const& key, JSON value)> fn) const
{ {
auto v = dynamic_cast<JSON_dictionary const*>(m->value.get()); auto v = dynamic_cast<JSON_dictionary const*>(m->value.get());
if (v == nullptr) { if (v == nullptr) {
@ -450,16 +440,13 @@ JSON::forEachArrayItem(std::function<void(JSON value)> fn) const
bool bool
JSON::checkSchema(JSON schema, std::list<std::string>& errors) JSON::checkSchema(JSON schema, std::list<std::string>& errors)
{ {
return checkSchemaInternal( return checkSchemaInternal(m->value.get(), schema.m->value.get(), 0, errors, "");
m->value.get(), schema.m->value.get(), 0, errors, "");
} }
bool bool
JSON::checkSchema( JSON::checkSchema(JSON schema, unsigned long flags, std::list<std::string>& errors)
JSON schema, unsigned long flags, std::list<std::string>& errors)
{ {
return checkSchemaInternal( return checkSchemaInternal(m->value.get(), schema.m->value.get(), flags, errors, "");
m->value.get(), schema.m->value.get(), flags, errors, "");
} }
bool bool
@ -495,8 +482,8 @@ JSON::checkSchemaInternal(
auto members = sch_dict->members; auto members = sch_dict->members;
std::string key; std::string key;
if ((members.size() == 1) && if ((members.size() == 1) &&
((key = members.begin()->first, key.length() > 2) && ((key = members.begin()->first, key.length() > 2) && (key.at(0) == '<') &&
(key.at(0) == '<') && (key.at(key.length() - 1) == '>'))) { (key.at(key.length() - 1) == '>'))) {
pattern_key = key; pattern_key = key;
} }
} }
@ -565,17 +552,12 @@ JSON::checkSchemaInternal(
} else { } else {
QTC::TC("libtests", "JSON schema array for single item"); QTC::TC("libtests", "JSON schema array for single item");
checkSchemaInternal( checkSchemaInternal(
this_v, this_v, sch_arr->elements.at(0).m->value.get(), flags, errors, prefix);
sch_arr->elements.at(0).m->value.get(),
flags,
errors,
prefix);
} }
} else if (!this_arr || (this_arr->elements.size() != n_elements)) { } else if (!this_arr || (this_arr->elements.size() != n_elements)) {
QTC::TC("libtests", "JSON schema array length mismatch"); QTC::TC("libtests", "JSON schema array length mismatch");
errors.push_back( errors.push_back(
err_prefix + " is supposed to be an array of length " + err_prefix + " is supposed to be an array of length " + std::to_string(n_elements));
std::to_string(n_elements));
return false; return false;
} else { } else {
// A multi-element array in the schema must correspond to // A multi-element array in the schema must correspond to
@ -595,8 +577,7 @@ JSON::checkSchemaInternal(
} }
} else if (!sch_str) { } else if (!sch_str) {
QTC::TC("libtests", "JSON schema other type"); QTC::TC("libtests", "JSON schema other type");
errors.push_back( errors.push_back(err_prefix + " schema value is not dictionary, array, or string");
err_prefix + " schema value is not dictionary, array, or string");
return false; return false;
} }
@ -736,8 +717,7 @@ JSONParser::handle_u_code(
" surrogate"); " surrogate");
} }
high_offset = 0; high_offset = 0;
codepoint = codepoint = 0x10000U + ((high_surrogate & 0x3FFU) << 10U) + (codepoint & 0x3FF);
0x10000U + ((high_surrogate & 0x3FFU) << 10U) + (codepoint & 0x3FF);
result += QUtil::toUTF8(codepoint); result += QUtil::toUTF8(codepoint);
} else { } else {
result += QUtil::toUTF8(codepoint); result += QUtil::toUTF8(codepoint);
@ -760,8 +740,8 @@ JSONParser::tokenError()
} else if (lex_state == ls_alpha) { } else if (lex_state == ls_alpha) {
QTC::TC("libtests", "JSON parse keyword bad character"); QTC::TC("libtests", "JSON parse keyword bad character");
throw std::runtime_error( throw std::runtime_error(
"JSON: offset " + std::to_string(offset) + "JSON: offset " + std::to_string(offset) + ": keyword: unexpected character " +
": keyword: unexpected character " + std::string(p, 1)); std::string(p, 1));
} else if (lex_state == ls_string) { } else if (lex_state == ls_string) {
QTC::TC("libtests", "JSON parse control char in string"); QTC::TC("libtests", "JSON parse control char in string");
throw std::runtime_error( throw std::runtime_error(
@ -775,8 +755,7 @@ JSONParser::tokenError()
} }
if (*p == '.') { if (*p == '.') {
if (lex_state == ls_number || lex_state == ls_number_e || if (lex_state == ls_number || lex_state == ls_number_e || lex_state == ls_number_e_sign) {
lex_state == ls_number_e_sign) {
QTC::TC("libtests", "JSON parse point after e"); QTC::TC("libtests", "JSON parse point after e");
throw std::runtime_error( throw std::runtime_error(
"JSON: offset " + std::to_string(offset) + "JSON: offset " + std::to_string(offset) +
@ -790,24 +769,21 @@ JSONParser::tokenError()
} else if (*p == 'e' || *p == 'E') { } else if (*p == 'e' || *p == 'E') {
QTC::TC("libtests", "JSON parse duplicate e"); QTC::TC("libtests", "JSON parse duplicate e");
throw std::runtime_error( throw std::runtime_error(
"JSON: offset " + std::to_string(offset) + "JSON: offset " + std::to_string(offset) + ": numeric literal: e already seen");
": numeric literal: e already seen");
} else if ((*p == '+') || (*p == '-')) { } else if ((*p == '+') || (*p == '-')) {
QTC::TC("libtests", "JSON parse unexpected sign"); QTC::TC("libtests", "JSON parse unexpected sign");
throw std::runtime_error( throw std::runtime_error(
"JSON: offset " + std::to_string(offset) + "JSON: offset " + std::to_string(offset) + ": numeric literal: unexpected sign");
": numeric literal: unexpected sign");
} else if (QUtil::is_space(*p) || strchr("{}[]:,", *p)) { } else if (QUtil::is_space(*p) || strchr("{}[]:,", *p)) {
QTC::TC("libtests", "JSON parse incomplete number"); QTC::TC("libtests", "JSON parse incomplete number");
throw std::runtime_error( throw std::runtime_error(
"JSON: offset " + std::to_string(offset) + "JSON: offset " + std::to_string(offset) + ": numeric literal: incomplete number");
": numeric literal: incomplete number");
} else { } else {
QTC::TC("libtests", "JSON parse numeric bad character"); QTC::TC("libtests", "JSON parse numeric bad character");
throw std::runtime_error( throw std::runtime_error(
"JSON: offset " + std::to_string(offset) + "JSON: offset " + std::to_string(offset) + ": numeric literal: unexpected character " +
": numeric literal: unexpected character " + std::string(p, 1)); std::string(p, 1));
} }
throw std::logic_error("JSON::tokenError : unhandled error"); throw std::logic_error("JSON::tokenError : unhandled error");
} }
@ -884,8 +860,7 @@ JSONParser::getToken()
} else { } else {
QTC::TC("libtests", "JSON parse null character"); QTC::TC("libtests", "JSON parse null character");
throw std::runtime_error( throw std::runtime_error(
"JSON: control or null character at offset " + "JSON: control or null character at offset " + std::to_string(offset));
std::to_string(offset));
} }
} else if (*p == ',') { } else if (*p == ',') {
if (lex_state == ls_top) { if (lex_state == ls_top) {
@ -968,8 +943,8 @@ JSONParser::getToken()
} else { } else {
QTC::TC("libtests", "JSON parse bad character"); QTC::TC("libtests", "JSON parse bad character");
throw std::runtime_error( throw std::runtime_error(
"JSON: offset " + std::to_string(offset) + "JSON: offset " + std::to_string(offset) + ": unexpected character " +
": unexpected character " + std::string(p, 1)); std::string(p, 1));
} }
break; break;
@ -994,8 +969,7 @@ JSONParser::getToken()
} else { } else {
QTC::TC("libtests", "JSON parse leading zero"); QTC::TC("libtests", "JSON parse leading zero");
throw std::runtime_error( throw std::runtime_error(
"JSON: offset " + std::to_string(offset) + "JSON: offset " + std::to_string(offset) + ": number with leading zero");
": number with leading zero");
} }
break; break;
@ -1127,20 +1101,14 @@ JSONParser::getToken()
tokenError(); tokenError();
} }
if (++u_count == 4) { if (++u_count == 4) {
handle_u_code( handle_u_code(u_value, offset - 5, high_surrogate, high_offset, token);
u_value,
offset - 5,
high_surrogate,
high_offset,
token);
lex_state = ls_string; lex_state = ls_string;
} }
ignore(); ignore();
break; break;
default: default:
throw std::logic_error( throw std::logic_error("JSONParser::getToken : trying to handle delimiter state");
"JSONParser::getToken : trying to handle delimiter state");
} }
} }
} }
@ -1205,19 +1173,16 @@ JSONParser::handleToken()
if (parser_state != ps_dict_after_key) { if (parser_state != ps_dict_after_key) {
QTC::TC("libtests", "JSON parse unexpected :"); QTC::TC("libtests", "JSON parse unexpected :");
throw std::runtime_error( throw std::runtime_error(
"JSON: offset " + std::to_string(offset) + "JSON: offset " + std::to_string(offset) + ": unexpected colon");
": unexpected colon");
} }
parser_state = ps_dict_after_colon; parser_state = ps_dict_after_colon;
return; return;
case ls_comma: case ls_comma:
if (!((parser_state == ps_dict_after_item) || if (!((parser_state == ps_dict_after_item) || (parser_state == ps_array_after_item))) {
(parser_state == ps_array_after_item))) {
QTC::TC("libtests", "JSON parse unexpected ,"); QTC::TC("libtests", "JSON parse unexpected ,");
throw std::runtime_error( throw std::runtime_error(
"JSON: offset " + std::to_string(offset) + "JSON: offset " + std::to_string(offset) + ": unexpected comma");
": unexpected comma");
} }
if (parser_state == ps_dict_after_item) { if (parser_state == ps_dict_after_item) {
parser_state = ps_dict_after_comma; parser_state = ps_dict_after_comma;
@ -1230,12 +1195,10 @@ JSONParser::handleToken()
return; return;
case ls_end_array: case ls_end_array:
if (!(parser_state == ps_array_begin || if (!(parser_state == ps_array_begin || parser_state == ps_array_after_item)) {
parser_state == ps_array_after_item)) {
QTC::TC("libtests", "JSON parse unexpected ]"); QTC::TC("libtests", "JSON parse unexpected ]");
throw std::runtime_error( throw std::runtime_error(
"JSON: offset " + std::to_string(offset) + "JSON: offset " + std::to_string(offset) + ": unexpected array end delimiter");
": unexpected array end delimiter");
} }
parser_state = stack.back().state; parser_state = stack.back().state;
tos.setEnd(offset); tos.setEnd(offset);
@ -1248,12 +1211,10 @@ JSONParser::handleToken()
return; return;
case ls_end_dict: case ls_end_dict:
if (!((parser_state == ps_dict_begin) || if (!((parser_state == ps_dict_begin) || (parser_state == ps_dict_after_item))) {
(parser_state == ps_dict_after_item))) {
QTC::TC("libtests", "JSON parse unexpected }"); QTC::TC("libtests", "JSON parse unexpected }");
throw std::runtime_error( throw std::runtime_error(
"JSON: offset " + std::to_string(offset) + "JSON: offset " + std::to_string(offset) + ": unexpected dictionary end delimiter");
": unexpected dictionary end delimiter");
} }
parser_state = stack.back().state; parser_state = stack.back().state;
tos.setEnd(offset); tos.setEnd(offset);
@ -1279,14 +1240,12 @@ JSONParser::handleToken()
} else { } else {
QTC::TC("libtests", "JSON parse invalid keyword"); QTC::TC("libtests", "JSON parse invalid keyword");
throw std::runtime_error( throw std::runtime_error(
"JSON: offset " + std::to_string(offset) + "JSON: offset " + std::to_string(offset) + ": invalid keyword " + token);
": invalid keyword " + token);
} }
break; break;
case ls_string: case ls_string:
if (parser_state == ps_dict_begin || if (parser_state == ps_dict_begin || parser_state == ps_dict_after_comma) {
parser_state == ps_dict_after_comma) {
dict_key = token; dict_key = token;
dict_key_offset = token_start; dict_key_offset = token_start;
parser_state = ps_dict_after_key; parser_state = ps_dict_after_key;
@ -1297,8 +1256,7 @@ JSONParser::handleToken()
break; break;
default: default:
throw std::logic_error( throw std::logic_error("JSONParser::handleToken : non-terminal lexer state encountered");
"JSONParser::handleToken : non-terminal lexer state encountered");
break; break;
} }
@ -1310,16 +1268,14 @@ JSONParser::handleToken()
case ps_dict_after_comma: case ps_dict_after_comma:
QTC::TC("libtests", "JSON parse string as dict key"); QTC::TC("libtests", "JSON parse string as dict key");
throw std::runtime_error( throw std::runtime_error(
"JSON: offset " + std::to_string(offset) + "JSON: offset " + std::to_string(offset) + ": expect string as dictionary key");
": expect string as dictionary key");
break; break;
case ps_dict_after_colon: case ps_dict_after_colon:
if (tos.checkDictionaryKeySeen(dict_key)) { if (tos.checkDictionaryKeySeen(dict_key)) {
QTC::TC("libtests", "JSON parse duplicate key"); QTC::TC("libtests", "JSON parse duplicate key");
throw std::runtime_error( throw std::runtime_error(
"JSON: offset " + std::to_string(dict_key_offset) + "JSON: offset " + std::to_string(dict_key_offset) + ": duplicated dictionary key");
": duplicated dictionary key");
} }
if (!reactor || !reactor->dictionaryItem(dict_key, item)) { if (!reactor || !reactor->dictionaryItem(dict_key, item)) {
tos.addDictionaryMember(dict_key, item); tos.addDictionaryMember(dict_key, item);
@ -1346,8 +1302,7 @@ JSONParser::handleToken()
case ps_dict_after_key: case ps_dict_after_key:
QTC::TC("libtests", "JSON parse expected colon"); QTC::TC("libtests", "JSON parse expected colon");
throw std::runtime_error( throw std::runtime_error("JSON: offset " + std::to_string(offset) + ": expected ':'");
"JSON: offset " + std::to_string(offset) + ": expected ':'");
break; break;
case ps_dict_after_item: case ps_dict_after_item:
@ -1363,8 +1318,7 @@ JSONParser::handleToken()
break; break;
case ps_done: case ps_done:
throw std::logic_error( throw std::logic_error("JSONParser::handleToken: unexpected parser state");
"JSONParser::handleToken: unexpected parser state");
} }
if (item.isDictionary() || item.isArray()) { if (item.isDictionary() || item.isArray()) {
@ -1387,8 +1341,7 @@ JSONParser::handleToken()
if (stack.size() > 500) { if (stack.size() > 500) {
throw std::runtime_error( throw std::runtime_error(
"JSON: offset " + std::to_string(offset) + "JSON: offset " + std::to_string(offset) + ": maximum object depth exceeded");
": maximum object depth exceeded");
} }
} }
} }

View File

@ -53,8 +53,7 @@ JSONHandler::addDictHandlers(json_handler_t start_fn, void_handler_t end_fn)
} }
void void
JSONHandler::addDictKeyHandler( JSONHandler::addDictKeyHandler(std::string const& key, std::shared_ptr<JSONHandler> dkh)
std::string const& key, std::shared_ptr<JSONHandler> dkh)
{ {
m->h.dict_handlers[key] = dkh; m->h.dict_handlers[key] = dkh;
} }
@ -67,9 +66,7 @@ JSONHandler::addFallbackDictHandler(std::shared_ptr<JSONHandler> fdh)
void void
JSONHandler::addArrayHandlers( JSONHandler::addArrayHandlers(
json_handler_t start_fn, json_handler_t start_fn, void_handler_t end_fn, std::shared_ptr<JSONHandler> ah)
void_handler_t end_fn,
std::shared_ptr<JSONHandler> ah)
{ {
m->h.array_start_handler = start_fn; m->h.array_start_handler = start_fn;
m->h.array_end_handler = end_fn; m->h.array_end_handler = end_fn;
@ -108,22 +105,19 @@ JSONHandler::handle(std::string const& path, JSON j)
if (path_base != ".") { if (path_base != ".") {
path_base += "."; path_base += ".";
} }
j.forEachDictItem( j.forEachDictItem([&path, &path_base, this](std::string const& k, JSON v) {
[&path, &path_base, this](std::string const& k, JSON v) { auto i = m->h.dict_handlers.find(k);
auto i = m->h.dict_handlers.find(k); if (i == m->h.dict_handlers.end()) {
if (i == m->h.dict_handlers.end()) { if (m->h.fallback_dict_handler.get()) {
if (m->h.fallback_dict_handler.get()) { m->h.fallback_dict_handler->handle(path_base + k, v);
m->h.fallback_dict_handler->handle(path_base + k, v);
} else {
QTC::TC("libtests", "JSONHandler unexpected key");
usage(
"JSON handler found unexpected key " + k +
" in object at " + path);
}
} else { } else {
i->second->handle(path_base + k, v); QTC::TC("libtests", "JSONHandler unexpected key");
usage("JSON handler found unexpected key " + k + " in object at " + path);
} }
}); } else {
i->second->handle(path_base + k, v);
}
});
m->h.dict_end_handler(path); m->h.dict_end_handler(path);
handled = true; handled = true;
} }
@ -131,8 +125,7 @@ JSONHandler::handle(std::string const& path, JSON j)
m->h.array_start_handler(path, j); 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) {
m->h.array_item_handler->handle( m->h.array_item_handler->handle(path + "[" + std::to_string(i) + "]", v);
path + "[" + std::to_string(i) + "]", v);
++i; ++i;
}); });
m->h.array_end_handler(path); m->h.array_end_handler(path);

View File

@ -81,8 +81,7 @@ MD5::encodeFile(char const* filename, qpdf_offset_t up_to_offset)
// 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);
@ -115,8 +114,7 @@ MD5::unparse()
this->crypto->MD5_finalize(); this->crypto->MD5_finalize();
Digest digest_val; Digest digest_val;
digest(digest_val); digest(digest_val);
return QUtil::hex_encode( return QUtil::hex_encode(std::string(reinterpret_cast<char*>(digest_val), 16));
std::string(reinterpret_cast<char*>(digest_val), 16));
} }
std::string std::string
@ -143,10 +141,7 @@ MD5::checkDataChecksum(char const* const checksum, char const* buf, size_t len)
} }
bool bool
MD5::checkFileChecksum( MD5::checkFileChecksum(char const* const checksum, 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 {

View File

@ -24,8 +24,7 @@ warn(QPDF& qpdf, QPDFObjectHandle& node, std::string const& msg)
static void static void
error(QPDF& qpdf, QPDFObjectHandle& node, std::string const& msg) error(QPDF& qpdf, QPDFObjectHandle& node, std::string const& msg)
{ {
throw QPDFExc( throw QPDFExc(qpdf_e_damaged_pdf, qpdf.getFilename(), get_description(node), 0, msg);
qpdf_e_damaged_pdf, qpdf.getFilename(), get_description(node), 0, msg);
} }
NNTreeIterator::NNTreeIterator(NNTreeImpl& impl) : NNTreeIterator::NNTreeIterator(NNTreeImpl& impl) :
@ -76,8 +75,7 @@ NNTreeIterator::updateIValue(bool allow_invalid)
} }
} }
NNTreeIterator::PathElement::PathElement( NNTreeIterator::PathElement::PathElement(QPDFObjectHandle const& node, int kid_number) :
QPDFObjectHandle const& node, int kid_number) :
node(node), node(node),
kid_number(kid_number) kid_number(kid_number)
{ {
@ -94,16 +92,14 @@ NNTreeIterator::getNextKid(PathElement& pe, bool backward)
if ((pe.kid_number >= 0) && (pe.kid_number < kids.getArrayNItems())) { if ((pe.kid_number >= 0) && (pe.kid_number < kids.getArrayNItems())) {
result = kids.getArrayItem(pe.kid_number); result = kids.getArrayItem(pe.kid_number);
if (result.isDictionary() && if (result.isDictionary() &&
(result.hasKey("/Kids") || (result.hasKey("/Kids") || result.hasKey(impl.details.itemsKey()))) {
result.hasKey(impl.details.itemsKey()))) {
found = true; found = true;
} else { } else {
QTC::TC("qpdf", "NNTree skip invalid kid"); QTC::TC("qpdf", "NNTree skip invalid kid");
warn( warn(
impl.qpdf, impl.qpdf,
pe.node, pe.node,
("skipping over invalid kid at index " + ("skipping over invalid kid at index " + std::to_string(pe.kid_number)));
std::to_string(pe.kid_number)));
} }
} else { } else {
result = QPDFObjectHandle::newNull(); result = QPDFObjectHandle::newNull();
@ -131,8 +127,7 @@ NNTreeIterator::increment(bool backward)
while (valid() && (!found_valid_key)) { while (valid() && (!found_valid_key)) {
this->item_number += backward ? -2 : 2; this->item_number += backward ? -2 : 2;
auto items = this->node.getKey(impl.details.itemsKey()); auto items = this->node.getKey(impl.details.itemsKey());
if ((this->item_number < 0) || if ((this->item_number < 0) || (this->item_number >= items.getArrayNItems())) {
(this->item_number >= items.getArrayNItems())) {
bool found = false; bool found = false;
setItemNumber(QPDFObjectHandle(), -1); setItemNumber(QPDFObjectHandle(), -1);
while (!(found || this->path.empty())) { while (!(found || this->path.empty())) {
@ -149,18 +144,13 @@ NNTreeIterator::increment(bool backward)
items = this->node.getKey(impl.details.itemsKey()); items = this->node.getKey(impl.details.itemsKey());
if (this->item_number + 1 >= items.getArrayNItems()) { if (this->item_number + 1 >= items.getArrayNItems()) {
QTC::TC("qpdf", "NNTree skip item at end of short items"); QTC::TC("qpdf", "NNTree skip item at end of short items");
warn( warn(impl.qpdf, this->node, "items array doesn't have enough elements");
impl.qpdf, } else if (!impl.details.keyValid(items.getArrayItem(this->item_number))) {
this->node,
"items array doesn't have enough elements");
} else if (!impl.details.keyValid(
items.getArrayItem(this->item_number))) {
QTC::TC("qpdf", "NNTree skip invalid key"); QTC::TC("qpdf", "NNTree skip invalid key");
warn( warn(
impl.qpdf, impl.qpdf,
this->node, this->node,
("item " + std::to_string(this->item_number) + ("item " + std::to_string(this->item_number) + " has the wrong type"));
" has the wrong type"));
} else { } else {
found_valid_key = true; found_valid_key = true;
} }
@ -169,8 +159,7 @@ NNTreeIterator::increment(bool backward)
} }
void void
NNTreeIterator::resetLimits( NNTreeIterator::resetLimits(QPDFObjectHandle node, std::list<PathElement>::iterator parent)
QPDFObjectHandle node, std::list<PathElement>::iterator parent)
{ {
bool done = false; bool done = false;
while (!done) { while (!done) {
@ -197,10 +186,8 @@ NNTreeIterator::resetLimits(
if (first_kid.isDictionary() && last_kid.isDictionary()) { if (first_kid.isDictionary() && last_kid.isDictionary()) {
auto first_limits = first_kid.getKey("/Limits"); auto first_limits = first_kid.getKey("/Limits");
auto last_limits = last_kid.getKey("/Limits"); auto last_limits = last_kid.getKey("/Limits");
if (first_limits.isArray() && if (first_limits.isArray() && (first_limits.getArrayNItems() >= 2) &&
(first_limits.getArrayNItems() >= 2) && last_limits.isArray() && (last_limits.getArrayNItems() >= 2)) {
last_limits.isArray() &&
(last_limits.getArrayNItems() >= 2)) {
first = first_limits.getArrayItem(0); first = first_limits.getArrayItem(0);
last = last_limits.getArrayItem(1); last = last_limits.getArrayItem(1);
} }
@ -214,8 +201,7 @@ NNTreeIterator::resetLimits(
if (olimits.isArray() && (olimits.getArrayNItems() == 2)) { if (olimits.isArray() && (olimits.getArrayNItems() == 2)) {
auto ofirst = olimits.getArrayItem(0); auto ofirst = olimits.getArrayItem(0);
auto olast = olimits.getArrayItem(1); auto olast = olimits.getArrayItem(1);
if (impl.details.keyValid(ofirst) && if (impl.details.keyValid(ofirst) && impl.details.keyValid(olast) &&
impl.details.keyValid(olast) &&
(impl.details.compareKeys(first, ofirst) == 0) && (impl.details.compareKeys(first, ofirst) == 0) &&
(impl.details.compareKeys(last, olast) == 0)) { (impl.details.compareKeys(last, olast) == 0)) {
QTC::TC("qpdf", "NNTree limits didn't change"); QTC::TC("qpdf", "NNTree limits didn't change");
@ -240,8 +226,7 @@ NNTreeIterator::resetLimits(
} }
void void
NNTreeIterator::split( NNTreeIterator::split(QPDFObjectHandle to_split, std::list<PathElement>::iterator parent)
QPDFObjectHandle to_split, std::list<PathElement>::iterator parent)
{ {
// Split some node along the path to the item pointed to by this // Split some node along the path to the item pointed to by this
// iterator, and adjust the iterator so it points to the same // iterator, and adjust the iterator so it points to the same
@ -272,8 +257,7 @@ NNTreeIterator::split(
// item_number: 0 // item_number: 0
if (!valid()) { if (!valid()) {
throw std::logic_error( throw std::logic_error("NNTreeIterator::split called an invalid iterator");
"NNTreeIterator::split called an invalid iterator");
} }
// Find the array we actually need to split, which is either this // Find the array we actually need to split, which is either this
@ -335,8 +319,7 @@ NNTreeIterator::split(
// non-root case so remaining logic can handle them in the // non-root case so remaining logic can handle them in the
// same way. // same way.
auto first_node = auto first_node = impl.qpdf.makeIndirectObject(QPDFObjectHandle::newDictionary());
impl.qpdf.makeIndirectObject(QPDFObjectHandle::newDictionary());
first_node.replaceKey(key, first_half); first_node.replaceKey(key, first_half);
QPDFObjectHandle new_kids = QPDFObjectHandle::newArray(); QPDFObjectHandle new_kids = QPDFObjectHandle::newArray();
new_kids.appendItem(first_node); new_kids.appendItem(first_node);
@ -371,8 +354,7 @@ NNTreeIterator::split(
resetLimits(to_split, parent); resetLimits(to_split, parent);
// Create a new node to contain the second half // Create a new node to contain the second half
QPDFObjectHandle second_node = QPDFObjectHandle second_node = impl.qpdf.makeIndirectObject(QPDFObjectHandle::newDictionary());
impl.qpdf.makeIndirectObject(QPDFObjectHandle::newDictionary());
second_node.replaceKey(key, second_half); second_node.replaceKey(key, second_half);
resetLimits(second_node, parent); resetLimits(second_node, parent);
@ -457,10 +439,7 @@ NNTreeIterator::remove()
auto items = this->node.getKey(impl.details.itemsKey()); auto items = this->node.getKey(impl.details.itemsKey());
int nitems = items.getArrayNItems(); int nitems = items.getArrayNItems();
if (this->item_number + 2 > nitems) { if (this->item_number + 2 > nitems) {
error( error(impl.qpdf, this->node, "found short items array while removing an item");
impl.qpdf,
this->node,
"found short items array while removing an item");
} }
items.eraseItem(this->item_number); items.eraseItem(this->item_number);
@ -491,8 +470,7 @@ NNTreeIterator::remove()
} else { } else {
// We already checked to ensure this condition would not // We already checked to ensure this condition would not
// happen. // happen.
throw std::logic_error( throw std::logic_error("NNTreeIterator::remove: item_number > nitems after erase");
"NNTreeIterator::remove: item_number > nitems after erase");
} }
return; return;
} }
@ -549,8 +527,7 @@ NNTreeIterator::remove()
// empty items array. // empty items array.
QTC::TC("qpdf", "NNTree non-flat tree is empty after remove"); QTC::TC("qpdf", "NNTree non-flat tree is empty after remove");
element->node.removeKey("/Kids"); element->node.removeKey("/Kids");
element->node.replaceKey( element->node.replaceKey(impl.details.itemsKey(), QPDFObjectHandle::newArray());
impl.details.itemsKey(), QPDFObjectHandle::newArray());
this->path.clear(); this->path.clear();
setItemNumber(impl.oh, -1); setItemNumber(impl.oh, -1);
done = true; done = true;
@ -645,20 +622,14 @@ NNTreeIterator::deepen(QPDFObjectHandle node, bool first, bool allow_empty)
while (!failed) { while (!failed) {
if (!seen.add(node)) { if (!seen.add(node)) {
QTC::TC("qpdf", "NNTree deepen: loop"); QTC::TC("qpdf", "NNTree deepen: loop");
warn( warn(impl.qpdf, node, "loop detected while traversing name/number tree");
impl.qpdf,
node,
"loop detected while traversing name/number tree");
failed = true; failed = true;
break; break;
} }
if (!node.isDictionary()) { if (!node.isDictionary()) {
QTC::TC("qpdf", "NNTree node is not a dictionary"); QTC::TC("qpdf", "NNTree node is not a dictionary");
warn( warn(impl.qpdf, node, "non-dictionary node while traversing name/number tree");
impl.qpdf,
node,
"non-dictionary node while traversing name/number tree");
failed = true; failed = true;
break; break;
} }
@ -703,8 +674,8 @@ NNTreeIterator::deepen(QPDFObjectHandle node, bool first, bool allow_empty)
warn( warn(
impl.qpdf, impl.qpdf,
node, node,
("name/number tree node has neither non-empty " + ("name/number tree node has neither non-empty " + impl.details.itemsKey() +
impl.details.itemsKey() + " nor /Kids")); " nor /Kids"));
failed = true; failed = true;
break; break;
} }
@ -717,10 +688,7 @@ NNTreeIterator::deepen(QPDFObjectHandle node, bool first, bool allow_empty)
} }
NNTreeImpl::NNTreeImpl( NNTreeImpl::NNTreeImpl(
NNTreeDetails const& details, NNTreeDetails const& details, QPDF& qpdf, QPDFObjectHandle& oh, bool auto_repair) :
QPDF& qpdf,
QPDFObjectHandle& oh,
bool auto_repair) :
details(details), details(details),
qpdf(qpdf), qpdf(qpdf),
split_threshold(32), split_threshold(32),
@ -763,8 +731,7 @@ NNTreeImpl::withinLimits(QPDFObjectHandle key, QPDFObjectHandle node)
int result = 0; int result = 0;
auto limits = node.getKey("/Limits"); auto limits = node.getKey("/Limits");
if (limits.isArray() && (limits.getArrayNItems() >= 2) && if (limits.isArray() && (limits.getArrayNItems() >= 2) &&
details.keyValid(limits.getArrayItem(0)) && details.keyValid(limits.getArrayItem(0)) && details.keyValid(limits.getArrayItem(1))) {
details.keyValid(limits.getArrayItem(1))) {
if (details.compareKeys(key, limits.getArrayItem(0)) < 0) { if (details.compareKeys(key, limits.getArrayItem(0)) < 0) {
result = -1; result = -1;
} else if (details.compareKeys(key, limits.getArrayItem(1)) > 0) { } else if (details.compareKeys(key, limits.getArrayItem(1)) > 0) {
@ -783,8 +750,7 @@ NNTreeImpl::binarySearch(
QPDFObjectHandle items, QPDFObjectHandle items,
int num_items, int num_items,
bool return_prev_if_not_found, bool return_prev_if_not_found,
int (NNTreeImpl::*compare)( int (NNTreeImpl::*compare)(QPDFObjectHandle& key, QPDFObjectHandle& arr, int item))
QPDFObjectHandle& key, QPDFObjectHandle& arr, int item))
{ {
int max_idx = 1; int max_idx = 1;
while (max_idx < num_items) { while (max_idx < num_items) {
@ -838,8 +804,7 @@ NNTreeImpl::binarySearch(
} }
int int
NNTreeImpl::compareKeyItem( NNTreeImpl::compareKeyItem(QPDFObjectHandle& key, QPDFObjectHandle& items, int idx)
QPDFObjectHandle& key, QPDFObjectHandle& items, int idx)
{ {
if (!((items.isArray() && (items.getArrayNItems() > (2 * idx)) && if (!((items.isArray() && (items.getArrayNItems() > (2 * idx)) &&
details.keyValid(items.getArrayItem(2 * idx))))) { details.keyValid(items.getArrayItem(2 * idx))))) {
@ -847,15 +812,13 @@ NNTreeImpl::compareKeyItem(
error( error(
qpdf, qpdf,
this->oh, this->oh,
("item at index " + std::to_string(2 * idx) + ("item at index " + std::to_string(2 * idx) + " is not the right type"));
" is not the right type"));
} }
return details.compareKeys(key, items.getArrayItem(2 * idx)); return details.compareKeys(key, items.getArrayItem(2 * idx));
} }
int int
NNTreeImpl::compareKeyKid( NNTreeImpl::compareKeyKid(QPDFObjectHandle& key, QPDFObjectHandle& kids, int idx)
QPDFObjectHandle& key, QPDFObjectHandle& kids, int idx)
{ {
if (!(kids.isArray() && (idx < kids.getArrayNItems()) && if (!(kids.isArray() && (idx < kids.getArrayNItems()) &&
kids.getArrayItem(idx).isDictionary())) { kids.getArrayItem(idx).isDictionary())) {
@ -875,8 +838,7 @@ NNTreeImpl::repair()
repl.insert(i.first, i.second); repl.insert(i.first, i.second);
} }
this->oh.replaceKey("/Kids", new_node.getKey("/Kids")); this->oh.replaceKey("/Kids", new_node.getKey("/Kids"));
this->oh.replaceKey( this->oh.replaceKey(details.itemsKey(), new_node.getKey(details.itemsKey()));
details.itemsKey(), new_node.getKey(details.itemsKey()));
} }
NNTreeImpl::iterator NNTreeImpl::iterator
@ -887,10 +849,7 @@ NNTreeImpl::find(QPDFObjectHandle key, bool return_prev_if_not_found)
} catch (QPDFExc& e) { } catch (QPDFExc& e) {
if (this->auto_repair) { if (this->auto_repair) {
QTC::TC("qpdf", "NNTree repair"); QTC::TC("qpdf", "NNTree repair");
warn( warn(qpdf, this->oh, std::string("attempting to repair after error: ") + e.what());
qpdf,
this->oh,
std::string("attempting to repair after error: ") + e.what());
repair(); repair();
return findInternal(key, return_prev_if_not_found); return findInternal(key, return_prev_if_not_found);
} else { } else {
@ -939,18 +898,13 @@ NNTreeImpl::findInternal(QPDFObjectHandle key, bool return_prev_if_not_found)
int nitems = items.isArray() ? items.getArrayNItems() : 0; int nitems = items.isArray() ? items.getArrayNItems() : 0;
if (nitems > 0) { if (nitems > 0) {
int idx = binarySearch( int idx = binarySearch(
key, key, items, nitems / 2, return_prev_if_not_found, &NNTreeImpl::compareKeyItem);
items,
nitems / 2,
return_prev_if_not_found,
&NNTreeImpl::compareKeyItem);
if (idx >= 0) { if (idx >= 0) {
result.setItemNumber(node, 2 * idx); result.setItemNumber(node, 2 * idx);
} }
break; break;
} else if (nkids > 0) { } else if (nkids > 0) {
int idx = binarySearch( int idx = binarySearch(key, kids, nkids, true, &NNTreeImpl::compareKeyKid);
key, kids, nkids, true, &NNTreeImpl::compareKeyKid);
if (idx == -1) { if (idx == -1) {
QTC::TC("qpdf", "NNTree -1 in binary search"); QTC::TC("qpdf", "NNTree -1 in binary search");
error( error(

View File

@ -10,11 +10,9 @@ OffsetInputSource::OffsetInputSource(
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");
} }
this->max_safe_offset = this->max_safe_offset = std::numeric_limits<qpdf_offset_t>::max() - global_offset;
std::numeric_limits<qpdf_offset_t>::max() - global_offset;
} }
qpdf_offset_t qpdf_offset_t
@ -51,8 +49,7 @@ OffsetInputSource::seek(qpdf_offset_t offset, int whence)
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,8 +7,7 @@ PDFVersion::PDFVersion() :
{ {
} }
PDFVersion::PDFVersion( PDFVersion::PDFVersion(int major_version, int minor_version, int extension_level) :
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)
@ -31,8 +30,7 @@ bool
PDFVersion::operator==(PDFVersion const& rhs) const PDFVersion::operator==(PDFVersion const& rhs) const
{ {
return ( return (
(this->major_version == rhs.major_version) && (this->major_version == rhs.major_version) && (this->minor_version == rhs.minor_version) &&
(this->minor_version == rhs.minor_version) &&
(this->extension_level == rhs.extension_level)); (this->extension_level == rhs.extension_level));
} }
@ -48,8 +46,7 @@ void
PDFVersion::getVersion(std::string& version, int& extension_level) const PDFVersion::getVersion(std::string& version, int& extension_level) const
{ {
extension_level = this->extension_level; extension_level = this->extension_level;
version = std::to_string(this->major_version) + "." + version = std::to_string(this->major_version) + "." + std::to_string(this->minor_version);
std::to_string(this->minor_version);
} }
int int

View File

@ -14,8 +14,7 @@ Pipeline::getNext(bool allow_null)
{ {
if ((this->next == nullptr) && (!allow_null)) { if ((this->next == nullptr) && (!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");
} }
return this->next; return this->next;
} }

View File

@ -117,8 +117,7 @@ Pl_AES_PDF::finish()
throw std::logic_error("buffer overflow in AES encryption" throw std::logic_error("buffer overflow in AES encryption"
" pipeline"); " pipeline");
} }
std::memset( std::memset(this->inbuf + this->offset, 0, 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);
@ -149,8 +148,7 @@ void
Pl_AES_PDF::flush(bool strip_padding) Pl_AES_PDF::flush(bool strip_padding)
{ {
if (this->offset != this->buf_size) { if (this->offset != this->buf_size) {
throw std::logic_error( throw std::logic_error("AES pipeline: flush called when buffer was not full");
"AES pipeline: flush called when buffer was not full");
} }
if (first) { if (first) {
@ -177,11 +175,7 @@ Pl_AES_PDF::flush(bool strip_padding)
} }
} }
this->crypto->rijndael_init( this->crypto->rijndael_init(
encrypt, encrypt, this->key.get(), key_bytes, this->cbc_mode, this->cbc_block);
this->key.get(),
key_bytes,
this->cbc_mode,
this->cbc_block);
if (return_after_init) { if (return_after_init) {
return; return;
} }

View File

@ -26,8 +26,7 @@ Pl_ASCII85Decoder::write(unsigned char const* buf, size_t len)
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]) { switch (buf[i]) {
@ -47,8 +46,7 @@ Pl_ASCII85Decoder::write(unsigned char const* buf, size_t len)
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];
@ -59,8 +57,7 @@ Pl_ASCII85Decoder::write(unsigned char const* buf, size_t len)
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) {
@ -93,10 +90,7 @@ Pl_ASCII85Decoder::flush()
lval >>= 8; lval >>= 8;
} }
QTC::TC( QTC::TC("libtests", "Pl_ASCII85Decoder partial flush", (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

@ -78,10 +78,7 @@ Pl_ASCIIHexDecoder::flush()
} }
auto ch = static_cast<unsigned char>((b[0] << 4) + b[1]); auto ch = static_cast<unsigned char>((b[0] << 4) + b[1]);
QTC::TC( QTC::TC("libtests", "Pl_ASCIIHexDecoder partial flush", (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

@ -91,8 +91,7 @@ void
Pl_Base64::flush_decode() Pl_Base64::flush_decode()
{ {
if (this->end_of_data) { if (this->end_of_data) {
throw std::runtime_error( throw std::runtime_error(getIdentifier() + ": base64 decode: data follows pad characters");
getIdentifier() + ": base64 decode: data follows pad characters");
} }
int pad = 0; int pad = 0;
int shift = 18; int shift = 18;
@ -110,14 +109,12 @@ Pl_Base64::flush_decode()
v = 62; v = 62;
} else if ((ch == '/') || (ch == '_')) { } else if ((ch == '/') || (ch == '_')) {
v = 63; v = 63;
} else if ( } else if ((ch == '=') && ((i == 3) || ((i == 2) && (this->buf[3] == '=')))) {
(ch == '=') && ((i == 3) || ((i == 2) && (this->buf[3] == '=')))) {
++pad; ++pad;
this->end_of_data = true; this->end_of_data = true;
v = 0; v = 0;
} else { } else {
throw std::runtime_error( throw std::runtime_error(getIdentifier() + ": base64 decode: invalid input");
getIdentifier() + ": base64 decode: invalid input");
} }
outval |= v << shift; outval |= v << shift;
shift -= 6; shift -= 6;

View File

@ -64,8 +64,7 @@ void
Pl_Buffer::getMallocBuffer(unsigned char** buf, size_t* len) Pl_Buffer::getMallocBuffer(unsigned char** buf, size_t* len)
{ {
if (!m->ready) { if (!m->ready) {
throw std::logic_error( throw std::logic_error("Pl_Buffer::getMallocBuffer() called when not ready");
"Pl_Buffer::getMallocBuffer() called when not ready");
} }
auto size = m->data.length(); auto size = m->data.length();
*len = size; *len = size;

View File

@ -182,15 +182,12 @@ term_pipeline_destination(j_compress_ptr cinfo)
} }
static void static void
jpeg_pipeline_dest( jpeg_pipeline_dest(j_compress_ptr cinfo, unsigned char* outbuffer, size_t size, Pipeline* next)
j_compress_ptr cinfo, unsigned char* outbuffer, size_t size, Pipeline* next)
{ {
cinfo->dest = static_cast<struct jpeg_destination_mgr*>( cinfo->dest = static_cast<struct jpeg_destination_mgr*>(
// line-break // line-break
(*cinfo->mem->alloc_small)( (*cinfo->mem->alloc_small)(
reinterpret_cast<j_common_ptr>(cinfo), reinterpret_cast<j_common_ptr>(cinfo), JPOOL_PERMANENT, sizeof(dct_pipeline_dest)));
JPOOL_PERMANENT,
sizeof(dct_pipeline_dest)));
auto* dest = reinterpret_cast<dct_pipeline_dest*>(cinfo->dest); auto* 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;
@ -243,9 +240,7 @@ jpeg_buffer_src(j_decompress_ptr cinfo, Buffer* buffer)
cinfo->src = reinterpret_cast<jpeg_source_mgr*>( cinfo->src = reinterpret_cast<jpeg_source_mgr*>(
// line-break // line-break
(*cinfo->mem->alloc_small)( (*cinfo->mem->alloc_small)(
reinterpret_cast<j_common_ptr>(cinfo), reinterpret_cast<j_common_ptr>(cinfo), JPOOL_PERMANENT, sizeof(jpeg_source_mgr)));
JPOOL_PERMANENT,
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;
@ -262,16 +257,12 @@ Pl_DCT::compress(void* cinfo_p, Buffer* b)
{ {
auto* cinfo = reinterpret_cast<jpeg_compress_struct*>(cinfo_p); auto* cinfo = reinterpret_cast<jpeg_compress_struct*>(cinfo_p);
#if ( \ #if ((defined(__GNUC__) && ((__GNUC__ * 100) + __GNUC_MINOR__) >= 406) || defined(__clang__))
(defined(__GNUC__) && ((__GNUC__ * 100) + __GNUC_MINOR__) >= 406) || \
defined(__clang__))
# pragma GCC diagnostic push # pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wold-style-cast" # pragma GCC diagnostic ignored "-Wold-style-cast"
#endif #endif
jpeg_create_compress(cinfo); jpeg_create_compress(cinfo);
#if ( \ #if ((defined(__GNUC__) && ((__GNUC__ * 100) + __GNUC_MINOR__) >= 406) || defined(__clang__))
(defined(__GNUC__) && ((__GNUC__ * 100) + __GNUC_MINOR__) >= 406) || \
defined(__clang__))
# pragma GCC diagnostic pop # pragma GCC diagnostic pop
#endif #endif
static int const BUF_SIZE = 65536; static int const BUF_SIZE = 65536;
@ -290,11 +281,9 @@ Pl_DCT::compress(void* cinfo_p, Buffer* b)
jpeg_start_compress(cinfo, TRUE); jpeg_start_compress(cinfo, TRUE);
unsigned int width = unsigned int width = cinfo->image_width * QIntC::to_uint(cinfo->input_components);
cinfo->image_width * QIntC::to_uint(cinfo->input_components);
size_t expected_size = QIntC::to_size(cinfo->image_height) * size_t expected_size = 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 = " + std::to_string(b->getSize()) + "Pl_DCT: image buffer size = " + std::to_string(b->getSize()) +
@ -316,16 +305,12 @@ Pl_DCT::decompress(void* cinfo_p, Buffer* b)
{ {
auto* cinfo = reinterpret_cast<jpeg_decompress_struct*>(cinfo_p); auto* cinfo = reinterpret_cast<jpeg_decompress_struct*>(cinfo_p);
#if ( \ #if ((defined(__GNUC__) && ((__GNUC__ * 100) + __GNUC_MINOR__) >= 406) || defined(__clang__))
(defined(__GNUC__) && ((__GNUC__ * 100) + __GNUC_MINOR__) >= 406) || \
defined(__clang__))
# pragma GCC diagnostic push # pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wold-style-cast" # pragma GCC diagnostic ignored "-Wold-style-cast"
#endif #endif
jpeg_create_decompress(cinfo); jpeg_create_decompress(cinfo);
#if ( \ #if ((defined(__GNUC__) && ((__GNUC__ * 100) + __GNUC_MINOR__) >= 406) || defined(__clang__))
(defined(__GNUC__) && ((__GNUC__ * 100) + __GNUC_MINOR__) >= 406) || \
defined(__clang__))
# pragma GCC diagnostic pop # pragma GCC diagnostic pop
#endif #endif
jpeg_buffer_src(cinfo, b); jpeg_buffer_src(cinfo, b);
@ -333,10 +318,9 @@ Pl_DCT::decompress(void* cinfo_p, Buffer* 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 = unsigned int width = cinfo->output_width * QIntC::to_uint(cinfo->output_components);
cinfo->output_width * QIntC::to_uint(cinfo->output_components); JSAMPARRAY buffer =
JSAMPARRAY buffer = (*cinfo->mem->alloc_sarray)( (*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) {

View File

@ -54,10 +54,7 @@ Pl_Flate::Members::~Members()
} }
Pl_Flate::Pl_Flate( Pl_Flate::Pl_Flate(
char const* identifier, char const* identifier, Pipeline* next, action_e action, unsigned int out_bufsize_int) :
Pipeline* next,
action_e action,
unsigned int out_bufsize_int) :
Pipeline(identifier, next), Pipeline(identifier, next),
m(new Members(QIntC::to_size(out_bufsize_int), action)) m(new Members(QIntC::to_size(out_bufsize_int), action))
{ {
@ -88,8 +85,7 @@ Pl_Flate::write(unsigned char const* data, size_t len)
{ {
if (m->outbuf == nullptr) { if (m->outbuf == nullptr) {
throw std::logic_error( throw std::logic_error(
this->identifier + this->identifier + ": Pl_Flate: write() called after finish() called");
": Pl_Flate: write() called after finish() called");
} }
// Write in chunks in case len is too big to fit in an int. // Write in chunks in case len is too big to fit in an int.
@ -99,8 +95,7 @@ Pl_Flate::write(unsigned char const* data, size_t len)
unsigned char const* buf = data; unsigned char const* buf = data;
while (bytes_left > 0) { while (bytes_left > 0) {
size_t bytes = (bytes_left >= max_bytes ? max_bytes : bytes_left); size_t bytes = (bytes_left >= max_bytes ? max_bytes : bytes_left);
handleData( handleData(buf, bytes, (m->action == a_inflate ? Z_SYNC_FLUSH : Z_NO_FLUSH));
buf, bytes, (m->action == a_inflate ? Z_SYNC_FLUSH : Z_NO_FLUSH));
bytes_left -= bytes; bytes_left -= bytes;
buf += bytes; buf += bytes;
} }
@ -124,9 +119,7 @@ Pl_Flate::handleData(unsigned char const* data, size_t len, int flush)
// deflateInit and inflateInit are macros that use old-style // deflateInit and inflateInit are macros that use old-style
// casts. // casts.
#if ( \ #if ((defined(__GNUC__) && ((__GNUC__ * 100) + __GNUC_MINOR__) >= 406) || defined(__clang__))
(defined(__GNUC__) && ((__GNUC__ * 100) + __GNUC_MINOR__) >= 406) || \
defined(__clang__))
# pragma GCC diagnostic push # pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wold-style-cast" # pragma GCC diagnostic ignored "-Wold-style-cast"
#endif #endif
@ -135,9 +128,7 @@ Pl_Flate::handleData(unsigned char const* data, size_t len, int flush)
} else { } else {
err = inflateInit(&zstream); err = inflateInit(&zstream);
} }
#if ( \ #if ((defined(__GNUC__) && ((__GNUC__ * 100) + __GNUC_MINOR__) >= 406) || defined(__clang__))
(defined(__GNUC__) && ((__GNUC__ * 100) + __GNUC_MINOR__) >= 406) || \
defined(__clang__))
# pragma GCC diagnostic pop # pragma GCC diagnostic pop
#endif #endif
@ -171,8 +162,7 @@ Pl_Flate::handleData(unsigned char const* data, size_t len, int flush)
// least one in qpdf's test suite). In some cases, we want // least one in qpdf's test suite). In some cases, we want
// to know about this, because it indicates incorrect // to know about this, because it indicates incorrect
// compression, so call a callback if provided. // compression, so call a callback if provided.
this->warn( this->warn("input stream is complete but output may still be valid", err);
"input stream is complete but output may still be valid", err);
done = true; done = true;
break; break;
@ -188,8 +178,7 @@ Pl_Flate::handleData(unsigned char const* data, size_t len, int flush)
// needed, so we're done for now. // needed, so we're done for now.
done = true; done = true;
} }
uLong ready = uLong ready = QIntC::to_ulong(m->out_bufsize - zstream.avail_out);
QIntC::to_ulong(m->out_bufsize - zstream.avail_out);
if (ready > 0) { if (ready > 0) {
this->getNext()->write(m->outbuf.get(), ready); this->getNext()->write(m->outbuf.get(), ready);
zstream.next_out = m->outbuf.get(); zstream.next_out = m->outbuf.get();
@ -249,10 +238,8 @@ Pl_Flate::checkError(char const* prefix, int error_code)
{ {
z_stream& zstream = *(static_cast<z_stream*>(m->zdata)); z_stream& zstream = *(static_cast<z_stream*>(m->zdata));
if (error_code != Z_OK) { if (error_code != Z_OK) {
char const* action_str = char const* action_str = (m->action == a_deflate ? "deflate" : "inflate");
(m->action == a_deflate ? "deflate" : "inflate"); std::string msg = this->identifier + ": " + action_str + ": " + prefix + ": ";
std::string msg =
this->identifier + ": " + action_str + ": " + prefix + ": ";
if (zstream.msg) { if (zstream.msg) {
msg += zstream.msg; msg += zstream.msg;
@ -283,8 +270,7 @@ Pl_Flate::checkError(char const* prefix, int error_code)
break; break;
default: default:
msg += std::string("zlib unknown error (") + msg += std::string("zlib unknown error (") + std::to_string(error_code) + ")";
std::to_string(error_code) + ")";
break; break;
} }
} }

View File

@ -13,8 +13,7 @@ Pl_Function::Pl_Function(char const* identifier, Pipeline* next, writer_t fn) :
{ {
} }
Pl_Function::Pl_Function( Pl_Function::Pl_Function(char const* identifier, Pipeline* next, writer_c_t fn, void* udata) :
char const* identifier, Pipeline* next, writer_c_t fn, void* udata) :
Pipeline(identifier, next), Pipeline(identifier, next),
m(new Members(nullptr)) m(new Members(nullptr))
{ {
@ -22,14 +21,12 @@ Pl_Function::Pl_Function(
int code = fn(data, len, udata); int code = fn(data, len, udata);
if (code != 0) { if (code != 0) {
throw std::runtime_error( throw std::runtime_error(
std::string(identifier) + " function returned code " + std::string(identifier) + " function returned code " + std::to_string(code));
std::to_string(code));
} }
}; };
} }
Pl_Function::Pl_Function( Pl_Function::Pl_Function(char const* identifier, Pipeline* next, writer_c_char_t fn, void* udata) :
char const* identifier, Pipeline* next, writer_c_char_t fn, void* udata) :
Pipeline(identifier, next), Pipeline(identifier, next),
m(new Members(nullptr)) m(new Members(nullptr))
{ {
@ -37,8 +34,7 @@ Pl_Function::Pl_Function(
int code = fn(reinterpret_cast<char const*>(data), len, udata); int code = fn(reinterpret_cast<char const*>(data), len, udata);
if (code != 0) { if (code != 0) {
throw std::runtime_error( throw std::runtime_error(
std::string(identifier) + " function returned code " + std::string(identifier) + " function returned code " + std::to_string(code));
std::to_string(code));
} }
}; };
} }

View File

@ -6,8 +6,7 @@
#include <cstring> #include <cstring>
#include <stdexcept> #include <stdexcept>
Pl_LZWDecoder::Pl_LZWDecoder( Pl_LZWDecoder::Pl_LZWDecoder(char const* identifier, Pipeline* next, bool early_code_change) :
char const* identifier, Pipeline* next, bool early_code_change) :
Pipeline(identifier, next), Pipeline(identifier, next),
code_size(9), code_size(9),
next(0), next(0),
@ -90,15 +89,13 @@ Pl_LZWDecoder::getFirstChar(unsigned int code)
} else if (code > 257) { } else if (code > 257) {
unsigned int idx = code - 258; unsigned int idx = code - 258;
if (idx >= table.size()) { if (idx >= table.size()) {
throw std::runtime_error( throw std::runtime_error("Pl_LZWDecoder::getFirstChar: table overflow");
"Pl_LZWDecoder::getFirstChar: table overflow");
} }
Buffer& b = table.at(idx); Buffer& b = table.at(idx);
result = b.getBuffer()[0]; result = b.getBuffer()[0];
} else { } else {
throw std::runtime_error( throw std::runtime_error(
"Pl_LZWDecoder::getFirstChar called with invalid code (" + "Pl_LZWDecoder::getFirstChar called with invalid code (" + std::to_string(code) + ")");
std::to_string(code) + ")");
} }
return result; return result;
} }
@ -117,8 +114,7 @@ Pl_LZWDecoder::addToTable(unsigned char next)
} else if (this->last_code > 257) { } else if (this->last_code > 257) {
unsigned int idx = this->last_code - 258; unsigned int idx = this->last_code - 258;
if (idx >= table.size()) { if (idx >= table.size()) {
throw std::runtime_error( throw std::runtime_error("Pl_LZWDecoder::addToTable: table overflow");
"Pl_LZWDecoder::addToTable: table overflow");
} }
Buffer& b = table.at(idx); Buffer& b = table.at(idx);
last_data = b.getBuffer(); last_data = b.getBuffer();
@ -182,8 +178,7 @@ Pl_LZWDecoder::handleCode(unsigned int code)
} }
addToTable(next); addToTable(next);
unsigned int change_idx = new_idx + code_change_delta; unsigned int change_idx = new_idx + code_change_delta;
if ((change_idx == 511) || (change_idx == 1023) || if ((change_idx == 511) || (change_idx == 1023) || (change_idx == 2047)) {
(change_idx == 2047)) {
++this->code_size; ++this->code_size;
} }
} }
@ -194,8 +189,7 @@ Pl_LZWDecoder::handleCode(unsigned int code)
} else { } else {
unsigned int idx = code - 258; unsigned int idx = code - 258;
if (idx >= table.size()) { if (idx >= table.size()) {
throw std::runtime_error( throw std::runtime_error("Pl_LZWDecoder::handleCode: table overflow");
"Pl_LZWDecoder::handleCode: table overflow");
} }
Buffer& b = table.at(idx); Buffer& b = table.at(idx);
getNext()->write(b.getBuffer(), b.getSize()); getNext()->write(b.getBuffer(), b.getSize());

View File

@ -26,8 +26,7 @@ Pl_MD5::write(unsigned char const* buf, size_t len)
unsigned char const* data = buf; unsigned char const* data = buf;
while (bytes_left > 0) { while (bytes_left > 0) {
size_t bytes = (bytes_left >= max_bytes ? max_bytes : bytes_left); size_t bytes = (bytes_left >= max_bytes ? max_bytes : bytes_left);
this->md5.encodeDataIncrementally( this->md5.encodeDataIncrementally(reinterpret_cast<char const*>(data), bytes);
reinterpret_cast<char const*>(data), bytes);
bytes_left -= bytes; bytes_left -= bytes;
data += bytes; data += bytes;
} }

View File

@ -22,8 +22,7 @@ Pl_OStream::~Pl_OStream()
void void
Pl_OStream::write(unsigned char const* buf, size_t len) Pl_OStream::write(unsigned char const* buf, size_t len)
{ {
m->os.write( m->os.write(reinterpret_cast<char const*>(buf), static_cast<std::streamsize>(len));
reinterpret_cast<char const*>(buf), static_cast<std::streamsize>(len));
} }
void void

View File

@ -29,36 +29,28 @@ Pl_PNGFilter::Pl_PNGFilter(
pos(0) pos(0)
{ {
if (samples_per_pixel < 1) { if (samples_per_pixel < 1) {
throw std::runtime_error( throw std::runtime_error("PNGFilter created with invalid samples_per_pixel");
"PNGFilter created with invalid samples_per_pixel");
} }
if (!((bits_per_sample == 1) || (bits_per_sample == 2) || if (!((bits_per_sample == 1) || (bits_per_sample == 2) || (bits_per_sample == 4) ||
(bits_per_sample == 4) || (bits_per_sample == 8) || (bits_per_sample == 8) || (bits_per_sample == 16))) {
(bits_per_sample == 16))) { throw std::runtime_error("PNGFilter created with invalid bits_per_sample not"
throw std::runtime_error( " 1, 2, 4, 8, or 16");
"PNGFilter created with invalid bits_per_sample not"
" 1, 2, 4, 8, or 16");
} }
this->bytes_per_pixel = ((bits_per_sample * samples_per_pixel) + 7) / 8; this->bytes_per_pixel = ((bits_per_sample * samples_per_pixel) + 7) / 8;
unsigned long long bpr = unsigned long long bpr = ((columns * bits_per_sample * samples_per_pixel) + 7) / 8;
((columns * bits_per_sample * samples_per_pixel) + 7) / 8;
if ((bpr == 0) || (bpr > (UINT_MAX - 1))) { if ((bpr == 0) || (bpr > (UINT_MAX - 1))) {
throw std::runtime_error( throw std::runtime_error("PNGFilter created with invalid columns value");
"PNGFilter created with invalid columns value");
} }
this->bytes_per_row = bpr & UINT_MAX; this->bytes_per_row = bpr & UINT_MAX;
this->buf1 = this->buf1 = QUtil::make_shared_array<unsigned char>(this->bytes_per_row + 1);
QUtil::make_shared_array<unsigned char>(this->bytes_per_row + 1); this->buf2 = QUtil::make_shared_array<unsigned char>(this->bytes_per_row + 1);
this->buf2 =
QUtil::make_shared_array<unsigned char>(this->bytes_per_row + 1);
memset(this->buf1.get(), 0, this->bytes_per_row + 1); memset(this->buf1.get(), 0, this->bytes_per_row + 1);
memset(this->buf2.get(), 0, this->bytes_per_row + 1); memset(this->buf2.get(), 0, this->bytes_per_row + 1);
this->cur_row = this->buf1.get(); this->cur_row = this->buf1.get();
this->prev_row = this->buf2.get(); this->prev_row = this->buf2.get();
// number of bytes per incoming row // number of bytes per incoming row
this->incoming = this->incoming = (action == a_encode ? this->bytes_per_row : this->bytes_per_row + 1);
(action == a_encode ? this->bytes_per_row : this->bytes_per_row + 1);
} }
void void
@ -197,8 +189,8 @@ Pl_PNGFilter::decodePaeth()
upper_left = above_buffer[i - bpp]; upper_left = above_buffer[i - bpp];
} }
buffer[i] = static_cast<unsigned char>( buffer[i] =
buffer[i] + this->PaethPredictor(left, up, upper_left)); static_cast<unsigned char>(buffer[i] + this->PaethPredictor(left, up, upper_left));
} }
} }
@ -227,8 +219,7 @@ Pl_PNGFilter::encodeRow()
getNext()->write(&ch, 1); getNext()->write(&ch, 1);
if (this->prev_row) { if (this->prev_row) {
for (unsigned int i = 0; i < this->bytes_per_row; ++i) { for (unsigned int i = 0; i < this->bytes_per_row; ++i) {
ch = static_cast<unsigned char>( ch = static_cast<unsigned char>(this->cur_row[i] - this->prev_row[i]);
this->cur_row[i] - this->prev_row[i]);
getNext()->write(&ch, 1); getNext()->write(&ch, 1);
} }
} else { } else {

View File

@ -11,15 +11,12 @@ Pl_QPDFTokenizer::Members::Members() :
} }
Pl_QPDFTokenizer::Pl_QPDFTokenizer( Pl_QPDFTokenizer::Pl_QPDFTokenizer(
char const* identifier, char const* identifier, QPDFObjectHandle::TokenFilter* filter, Pipeline* next) :
QPDFObjectHandle::TokenFilter* filter,
Pipeline* next) :
Pipeline(identifier, next), Pipeline(identifier, next),
m(new Members) m(new Members)
{ {
m->filter = filter; m->filter = filter;
QPDFObjectHandle::TokenFilter::PipelineAccessor::setPipeline( QPDFObjectHandle::TokenFilter::PipelineAccessor::setPipeline(m->filter, next);
m->filter, next);
m->tokenizer.allowEOF(); m->tokenizer.allowEOF();
m->tokenizer.includeIgnorable(); m->tokenizer.includeIgnorable();
} }
@ -45,8 +42,8 @@ Pl_QPDFTokenizer::finish()
new BufferInputSource("tokenizer data", m->buf.getBuffer(), true)); new BufferInputSource("tokenizer data", m->buf.getBuffer(), true));
while (true) { while (true) {
QPDFTokenizer::Token token = m->tokenizer.readToken( QPDFTokenizer::Token token =
input, "offset " + std::to_string(input->tell()), true); m->tokenizer.readToken(input, "offset " + std::to_string(input->tell()), true);
m->filter->handleToken(token); m->filter->handleToken(token);
if (token.getType() == QPDFTokenizer::tt_eof) { if (token.getType() == QPDFTokenizer::tt_eof) {
break; break;
@ -56,15 +53,13 @@ Pl_QPDFTokenizer::finish()
input->read(&ch, 1); input->read(&ch, 1);
m->filter->handleToken( m->filter->handleToken(
// line-break // line-break
QPDFTokenizer::Token( QPDFTokenizer::Token(QPDFTokenizer::tt_space, std::string(1, ch)));
QPDFTokenizer::tt_space, std::string(1, ch)));
QTC::TC("qpdf", "Pl_QPDFTokenizer found ID"); QTC::TC("qpdf", "Pl_QPDFTokenizer found ID");
m->tokenizer.expectInlineImage(input); m->tokenizer.expectInlineImage(input);
} }
} }
m->filter->handleEOF(); m->filter->handleEOF();
QPDFObjectHandle::TokenFilter::PipelineAccessor::setPipeline( QPDFObjectHandle::TokenFilter::PipelineAccessor::setPipeline(m->filter, nullptr);
m->filter, nullptr);
Pipeline* next = this->getNext(true); Pipeline* next = this->getNext(true);
if (next) { if (next) {
next->finish(); next->finish();

View File

@ -19,17 +19,14 @@ void
Pl_RC4::write(unsigned char const* data, size_t len) Pl_RC4::write(unsigned char const* data, size_t len)
{ {
if (this->outbuf == nullptr) { if (this->outbuf == nullptr) {
throw std::logic_error( throw std::logic_error(this->identifier + ": Pl_RC4: write() called after finish() called");
this->identifier +
": Pl_RC4: write() called after finish() called");
} }
size_t bytes_left = len; size_t bytes_left = len;
unsigned char const* p = data; unsigned char const* p = data;
while (bytes_left > 0) { while (bytes_left > 0) {
size_t bytes = size_t bytes = (bytes_left < this->out_bufsize ? bytes_left : out_bufsize);
(bytes_left < this->out_bufsize ? bytes_left : out_bufsize);
bytes_left -= bytes; bytes_left -= bytes;
// lgtm[cpp/weak-cryptographic-algorithm] // lgtm[cpp/weak-cryptographic-algorithm]
rc4.process(p, bytes, outbuf.get()); rc4.process(p, bytes, outbuf.get());

View File

@ -10,8 +10,7 @@ Pl_RunLength::Members::Members(action_e action) :
{ {
} }
Pl_RunLength::Pl_RunLength( Pl_RunLength::Pl_RunLength(char const* identifier, Pipeline* next, action_e action) :
char const* identifier, Pipeline* next, action_e action) :
Pipeline(identifier, next), Pipeline(identifier, next),
m(new Members(action)) m(new Members(action))
{ {
@ -38,17 +37,12 @@ Pl_RunLength::encode(unsigned char const* data, size_t len)
{ {
for (size_t i = 0; i < len; ++i) { for (size_t i = 0; i < len; ++i) {
if ((m->state == st_top) != (m->length <= 1)) { if ((m->state == st_top) != (m->length <= 1)) {
throw std::logic_error( throw std::logic_error("Pl_RunLength::encode: state/length inconsistency");
"Pl_RunLength::encode: state/length inconsistency");
} }
unsigned char ch = data[i]; unsigned char ch = data[i];
if ((m->length > 0) && if ((m->length > 0) && ((m->state == st_copying) || (m->length < 128)) &&
((m->state == st_copying) || (m->length < 128)) &&
(ch == m->buf[m->length - 1])) { (ch == m->buf[m->length - 1])) {
QTC::TC( QTC::TC("libtests", "Pl_RunLength: switch to run", (m->length == 128) ? 0 : 1);
"libtests",
"Pl_RunLength: switch to run",
(m->length == 128) ? 0 : 1);
if (m->state == st_copying) { if (m->state == st_copying) {
--m->length; --m->length;
flush_encode(); flush_encode();
@ -124,8 +118,7 @@ Pl_RunLength::flush_encode()
} }
if (m->state == st_run) { if (m->state == st_run) {
if ((m->length < 2) || (m->length > 128)) { if ((m->length < 2) || (m->length > 128)) {
throw std::logic_error( throw std::logic_error("Pl_RunLength: invalid length in flush_encode for run");
"Pl_RunLength: invalid length in flush_encode for run");
} }
auto ch = static_cast<unsigned char>(257 - m->length); auto ch = static_cast<unsigned char>(257 - m->length);
this->getNext()->write(&ch, 1); this->getNext()->write(&ch, 1);

View File

@ -51,8 +51,7 @@ void
Pl_SHA2::resetBits(int bits) Pl_SHA2::resetBits(int bits)
{ {
if (this->in_progress) { if (this->in_progress) {
throw std::logic_error( throw std::logic_error("bit reset requested for in-progress SHA2 Pipeline");
"bit reset requested for in-progress SHA2 Pipeline");
} }
this->crypto = QPDFCryptoProvider::getImpl(); this->crypto = QPDFCryptoProvider::getImpl();
this->crypto->SHA2_init(bits); this->crypto->SHA2_init(bits);
@ -62,8 +61,7 @@ std::string
Pl_SHA2::getRawDigest() Pl_SHA2::getRawDigest()
{ {
if (this->in_progress) { if (this->in_progress) {
throw std::logic_error( throw std::logic_error("digest requested for in-progress SHA2 Pipeline");
"digest requested for in-progress SHA2 Pipeline");
} }
return this->crypto->SHA2_digest(); return this->crypto->SHA2_digest();
} }
@ -72,8 +70,7 @@ std::string
Pl_SHA2::getHexDigest() Pl_SHA2::getHexDigest()
{ {
if (this->in_progress) { if (this->in_progress) {
throw std::logic_error( throw std::logic_error("digest requested for in-progress SHA2 Pipeline");
"digest requested for in-progress SHA2 Pipeline");
} }
return QUtil::hex_encode(getRawDigest()); return QUtil::hex_encode(getRawDigest());
} }

View File

@ -30,8 +30,7 @@ Pl_StdioFile::write(unsigned char const* buf, size_t len)
while (len > 0) { while (len > 0) {
so_far = fwrite(buf, 1, len, m->file); so_far = fwrite(buf, 1, len, m->file);
if (so_far == 0) { if (so_far == 0) {
QUtil::throw_system_error( QUtil::throw_system_error(this->identifier + ": Pl_StdioFile::write");
this->identifier + ": Pl_StdioFile::write");
} else { } else {
buf += so_far; buf += so_far;
len -= so_far; len -= so_far;
@ -43,7 +42,6 @@ void
Pl_StdioFile::finish() Pl_StdioFile::finish()
{ {
if ((fflush(m->file) == -1) && (errno == EBADF)) { if ((fflush(m->file) == -1) && (errno == EBADF)) {
throw std::logic_error( throw std::logic_error(this->identifier + ": Pl_StdioFile::finish: stream already closed");
this->identifier + ": Pl_StdioFile::finish: stream already closed");
} }
} }

View File

@ -25,23 +25,17 @@ Pl_TIFFPredictor::Pl_TIFFPredictor(
pos(0) pos(0)
{ {
if (samples_per_pixel < 1) { if (samples_per_pixel < 1) {
throw std::runtime_error( throw std::runtime_error("TIFFPredictor created with invalid samples_per_pixel");
"TIFFPredictor created with invalid samples_per_pixel");
} }
if ((bits_per_sample < 1) || if ((bits_per_sample < 1) || (bits_per_sample > (8 * (sizeof(unsigned long long))))) {
(bits_per_sample > (8 * (sizeof(unsigned long long))))) { throw std::runtime_error("TIFFPredictor created with invalid bits_per_sample");
throw std::runtime_error(
"TIFFPredictor created with invalid bits_per_sample");
} }
unsigned long long bpr = unsigned long long bpr = ((columns * bits_per_sample * samples_per_pixel) + 7) / 8;
((columns * bits_per_sample * samples_per_pixel) + 7) / 8;
if ((bpr == 0) || (bpr > (UINT_MAX - 1))) { if ((bpr == 0) || (bpr > (UINT_MAX - 1))) {
throw std::runtime_error( throw std::runtime_error("TIFFPredictor created with invalid columns value");
"TIFFPredictor created with invalid columns value");
} }
this->bytes_per_row = bpr & UINT_MAX; this->bytes_per_row = bpr & UINT_MAX;
this->cur_row = this->cur_row = QUtil::make_shared_array<unsigned char>(this->bytes_per_row);
QUtil::make_shared_array<unsigned char>(this->bytes_per_row);
memset(this->cur_row.get(), 0, this->bytes_per_row); memset(this->cur_row.get(), 0, this->bytes_per_row);
} }
@ -72,10 +66,7 @@ Pl_TIFFPredictor::write(unsigned char const* data, size_t len)
void void
Pl_TIFFPredictor::processRow() Pl_TIFFPredictor::processRow()
{ {
QTC::TC( QTC::TC("libtests", "Pl_TIFFPredictor processRow", (action == a_decode ? 0 : 1));
"libtests",
"Pl_TIFFPredictor processRow",
(action == a_decode ? 0 : 1));
BitWriter bw(this->getNext()); BitWriter bw(this->getNext());
BitStream in(this->cur_row.get(), this->bytes_per_row); BitStream in(this->cur_row.get(), this->bytes_per_row);
std::vector<long long> prev; std::vector<long long> prev;

View File

@ -105,11 +105,10 @@ namespace
void void
throwException() throwException()
{ {
throw std::logic_error( throw std::logic_error("QPDF operation attempted on a QPDF object with no input "
"QPDF operation attempted on a QPDF object with no input " "source."
"source." " QPDF operations are invalid before processFile (or another"
" QPDF operations are invalid before processFile (or another" " process method) or after closeInputSource");
" process method) or after closeInputSource");
} }
}; };
} // namespace } // namespace
@ -130,8 +129,7 @@ QPDF::ForeignStreamData::ForeignStreamData(
{ {
} }
QPDF::CopiedStreamDataProvider::CopiedStreamDataProvider( QPDF::CopiedStreamDataProvider::CopiedStreamDataProvider(QPDF& destination_qpdf) :
QPDF& destination_qpdf) :
QPDFObjectHandle::StreamDataProvider(true), QPDFObjectHandle::StreamDataProvider(true),
destination_qpdf(destination_qpdf) destination_qpdf(destination_qpdf)
{ {
@ -139,10 +137,7 @@ QPDF::CopiedStreamDataProvider::CopiedStreamDataProvider(
bool bool
QPDF::CopiedStreamDataProvider::provideStreamData( QPDF::CopiedStreamDataProvider::provideStreamData(
QPDFObjGen const& og, QPDFObjGen const& og, Pipeline* pipeline, bool suppress_warnings, bool will_retry)
Pipeline* pipeline,
bool suppress_warnings,
bool will_retry)
{ {
std::shared_ptr<ForeignStreamData> foreign_data = foreign_stream_data[og]; std::shared_ptr<ForeignStreamData> foreign_data = foreign_stream_data[og];
bool result = false; bool result = false;
@ -154,8 +149,7 @@ QPDF::CopiedStreamDataProvider::provideStreamData(
auto foreign_stream = foreign_streams[og]; auto foreign_stream = foreign_streams[og];
result = foreign_stream.pipeStreamData( result = foreign_stream.pipeStreamData(
pipeline, nullptr, 0, qpdf_dl_none, suppress_warnings, will_retry); pipeline, nullptr, 0, qpdf_dl_none, suppress_warnings, will_retry);
QTC::TC( QTC::TC("qpdf", "QPDF copy foreign with foreign_stream", result ? 0 : 1);
"qpdf", "QPDF copy foreign with foreign_stream", result ? 0 : 1);
} }
return result; return result;
} }
@ -169,8 +163,7 @@ QPDF::CopiedStreamDataProvider::registerForeignStream(
void void
QPDF::CopiedStreamDataProvider::registerForeignStream( QPDF::CopiedStreamDataProvider::registerForeignStream(
QPDFObjGen const& local_og, QPDFObjGen const& local_og, std::shared_ptr<ForeignStreamData> foreign_stream)
std::shared_ptr<ForeignStreamData> foreign_stream)
{ {
this->foreign_stream_data[local_og] = foreign_stream; this->foreign_stream_data[local_og] = foreign_stream;
} }
@ -269,8 +262,7 @@ QPDF::processFile(char const* filename, char const* password)
} }
void void
QPDF::processFile( QPDF::processFile(char const* description, FILE* filep, bool close_file, char const* password)
char const* description, FILE* filep, bool close_file, char const* password)
{ {
auto* fi = new FileInputSource(description, filep, close_file); auto* fi = new FileInputSource(description, filep, close_file);
processInputSource(std::shared_ptr<InputSource>(fi), password); processInputSource(std::shared_ptr<InputSource>(fi), password);
@ -278,24 +270,18 @@ QPDF::processFile(
void void
QPDF::processMemoryFile( QPDF::processMemoryFile(
char const* description, char const* description, char const* buf, size_t length, char const* password)
char const* buf,
size_t length,
char const* password)
{ {
processInputSource( processInputSource(
std::shared_ptr<InputSource>( std::shared_ptr<InputSource>(
// line-break // line-break
new BufferInputSource( new BufferInputSource(
description, description, new Buffer(QUtil::unsigned_char_pointer(buf), length), true)),
new Buffer(QUtil::unsigned_char_pointer(buf), length),
true)),
password); password);
} }
void void
QPDF::processInputSource( QPDF::processInputSource(std::shared_ptr<InputSource> source, char const* password)
std::shared_ptr<InputSource> source, char const* password)
{ {
m->file = source; m->file = source;
parse(password); parse(password);
@ -321,8 +307,7 @@ QPDF::emptyPDF()
void void
QPDF::registerStreamFilter( QPDF::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)
{ {
QPDF_Stream::registerStreamFilter(filter_name, factory); QPDF_Stream::registerStreamFilter(filter_name, factory);
} }
@ -434,8 +419,7 @@ QPDF::findHeader()
// offsets in the file are such that 0 points to the // offsets in the file are such that 0 points to the
// beginning of the header. // beginning of the header.
QTC::TC("qpdf", "QPDF global offset"); QTC::TC("qpdf", "QPDF global offset");
m->file = std::shared_ptr<InputSource>( m->file = std::shared_ptr<InputSource>(new OffsetInputSource(m->file, global_offset));
new OffsetInputSource(m->file, global_offset));
} }
} }
return valid; return valid;
@ -444,8 +428,7 @@ QPDF::findHeader()
bool bool
QPDF::findStartxref() QPDF::findStartxref()
{ {
if (readToken(m->file).isWord("startxref") && if (readToken(m->file).isWord("startxref") && readToken(m->file).isInteger()) {
readToken(m->file).isInteger()) {
// Position in front of offset token // Position in front of offset token
m->file->seek(m->file->getLastOffset(), SEEK_SET); m->file->seek(m->file->getLastOffset(), SEEK_SET);
return true; return true;
@ -479,8 +462,7 @@ QPDF::parse(char const* password)
PatternFinder sf(*this, &QPDF::findStartxref); PatternFinder sf(*this, &QPDF::findStartxref);
qpdf_offset_t xref_offset = 0; qpdf_offset_t xref_offset = 0;
if (m->file->findLast("startxref", start_offset, 0, sf)) { if (m->file->findLast("startxref", start_offset, 0, sf)) {
xref_offset = xref_offset = QUtil::string_to_ll(readToken(m->file).getValue().c_str());
QUtil::string_to_ll(readToken(m->file).getValue().c_str());
} }
try { try {
@ -493,8 +475,7 @@ QPDF::parse(char const* password)
} catch (QPDFExc&) { } catch (QPDFExc&) {
throw; throw;
} catch (std::exception& e) { } catch (std::exception& e) {
throw damagedPDF( throw damagedPDF("", 0, std::string("error reading xref: ") + e.what());
"", 0, std::string("error reading xref: ") + e.what());
} }
} catch (QPDFExc& e) { } catch (QPDFExc& e) {
if (m->attempt_recovery) { if (m->attempt_recovery) {
@ -515,9 +496,8 @@ QPDF::inParse(bool v)
if (m->in_parse == v) { if (m->in_parse == v) {
// This happens if QPDFParser::parse tries to // This happens if QPDFParser::parse tries to
// resolve an indirect object while it is parsing. // resolve an indirect object while it is parsing.
throw std::logic_error( throw std::logic_error("QPDF: re-entrant parsing detected. This is a qpdf bug."
"QPDF: re-entrant parsing detected. This is a qpdf bug." " Please report at https://github.com/qpdf/qpdf/issues.");
" Please report at https://github.com/qpdf/qpdf/issues.");
} }
m->in_parse = v; m->in_parse = v;
} }
@ -590,22 +570,19 @@ QPDF::reconstruct_xref(QPDFExc& e)
qpdf_offset_t next_line_start = m->file->tell(); qpdf_offset_t next_line_start = m->file->tell();
m->file->seek(line_start, SEEK_SET); m->file->seek(line_start, SEEK_SET);
QPDFTokenizer::Token t1 = readToken(m->file, MAX_LEN); QPDFTokenizer::Token t1 = readToken(m->file, MAX_LEN);
qpdf_offset_t token_start = qpdf_offset_t token_start = m->file->tell() - toO(t1.getValue().length());
m->file->tell() - toO(t1.getValue().length());
if (token_start >= next_line_start) { if (token_start >= next_line_start) {
// don't process yet -- wait until we get to the line // don't process yet -- wait until we get to the line
// containing this token // containing this token
} else if (t1.isInteger()) { } else if (t1.isInteger()) {
QPDFTokenizer::Token t2 = readToken(m->file, MAX_LEN); QPDFTokenizer::Token t2 = readToken(m->file, MAX_LEN);
if ((t2.isInteger()) && if ((t2.isInteger()) && (readToken(m->file, MAX_LEN).isWord("obj"))) {
(readToken(m->file, MAX_LEN).isWord("obj"))) {
int obj = QUtil::string_to_int(t1.getValue().c_str()); int obj = QUtil::string_to_int(t1.getValue().c_str());
int gen = QUtil::string_to_int(t2.getValue().c_str()); int gen = QUtil::string_to_int(t2.getValue().c_str());
insertXrefEntry(obj, 1, token_start, gen, true); insertXrefEntry(obj, 1, token_start, gen, true);
} }
} else if (!m->trailer.isInitialized() && t1.isWord("trailer")) { } else if (!m->trailer.isInitialized() && t1.isWord("trailer")) {
QPDFObjectHandle t = QPDFObjectHandle t = readObject(m->file, "trailer", QPDFObjGen(), false);
readObject(m->file, "trailer", QPDFObjGen(), false);
if (!t.isDictionary()) { if (!t.isDictionary()) {
// Oh well. It was worth a try. // Oh well. It was worth a try.
} else { } else {
@ -623,10 +600,7 @@ QPDF::reconstruct_xref(QPDFExc& e)
// with bad startxref pointers even when they have object // with bad startxref pointers even when they have object
// streams. // streams.
throw damagedPDF( throw damagedPDF("", 0, "unable to find trailer dictionary while recovering damaged file");
"",
0,
"unable to find trailer dictionary while recovering damaged file");
} }
// We could iterate through the objects looking for streams and // We could iterate through the objects looking for streams and
@ -666,10 +640,7 @@ QPDF::read_xref(qpdf_offset_t xref_offset)
done = true; done = true;
} }
} else { } else {
QTC::TC( QTC::TC("qpdf", "QPDF eof skipping spaces before xref", skipped_space ? 0 : 1);
"qpdf",
"QPDF eof skipping spaces before xref",
skipped_space ? 0 : 1);
done = true; done = true;
} }
} }
@ -681,8 +652,7 @@ QPDF::read_xref(qpdf_offset_t xref_offset)
if ((strncmp(buf, "xref", 4) == 0) && QUtil::is_space(buf[4])) { if ((strncmp(buf, "xref", 4) == 0) && QUtil::is_space(buf[4])) {
if (skipped_space) { if (skipped_space) {
QTC::TC("qpdf", "QPDF xref skipped space"); QTC::TC("qpdf", "QPDF xref skipped space");
warn(damagedPDF( warn(damagedPDF("", 0, "extraneous whitespace seen before xref"));
"", 0, "extraneous whitespace seen before xref"));
} }
QTC::TC( QTC::TC(
"qpdf", "qpdf",
@ -724,8 +694,7 @@ QPDF::read_xref(qpdf_offset_t xref_offset)
"", "",
0, 0,
("reported number of objects (" + std::to_string(size) + ("reported number of objects (" + std::to_string(size) +
") is not one plus the highest object number (" + ") is not one plus the highest object number (" + std::to_string(max_obj) + ")")));
std::to_string(max_obj) + ")")));
} }
// We no longer need the deleted_objects table, so go ahead and // We no longer need the deleted_objects table, so go ahead and
@ -782,8 +751,7 @@ QPDF::parse_xrefFirst(std::string const& line, int& obj, int& num, int& bytes)
} }
bool bool
QPDF::parse_xrefEntry( QPDF::parse_xrefEntry(std::string const& line, qpdf_offset_t& f1, int& f2, char& type)
std::string const& line, qpdf_offset_t& f1, int& f2, char& type)
{ {
// is_space and is_digit both return false on '\0', so this will // is_space and is_digit both return false on '\0', so this will
// not overrun the null-terminated buffer. // not overrun the null-terminated buffer.
@ -891,8 +859,7 @@ QPDF::read_xrefTable(qpdf_offset_t xref_offset)
if (!parse_xrefEntry(xref_entry, f1, f2, type)) { if (!parse_xrefEntry(xref_entry, f1, f2, type)) {
QTC::TC("qpdf", "QPDF invalid xref entry"); QTC::TC("qpdf", "QPDF invalid xref entry");
throw damagedPDF( throw damagedPDF(
"xref table", "xref table", "invalid xref entry (obj=" + std::to_string(i) + ")");
"invalid xref entry (obj=" + std::to_string(i) + ")");
} }
if (type == 'f') { if (type == 'f') {
// Save deleted items until after we've checked the // Save deleted items until after we've checked the
@ -911,8 +878,7 @@ QPDF::read_xrefTable(qpdf_offset_t xref_offset)
} }
// Set offset to previous xref table if any // Set offset to previous xref table if any
QPDFObjectHandle cur_trailer = QPDFObjectHandle cur_trailer = readObject(m->file, "trailer", QPDFObjGen(), false);
readObject(m->file, "trailer", QPDFObjGen(), false);
if (!cur_trailer.isDictionary()) { if (!cur_trailer.isDictionary()) {
QTC::TC("qpdf", "QPDF missing trailer"); QTC::TC("qpdf", "QPDF missing trailer");
throw damagedPDF("", "expected trailer dictionary"); throw damagedPDF("", "expected trailer dictionary");
@ -927,8 +893,7 @@ QPDF::read_xrefTable(qpdf_offset_t xref_offset)
} }
if (!m->trailer.getKey("/Size").isInteger()) { if (!m->trailer.getKey("/Size").isInteger()) {
QTC::TC("qpdf", "QPDF trailer size not integer"); QTC::TC("qpdf", "QPDF trailer size not integer");
throw damagedPDF( throw damagedPDF("trailer", "/Size key in trailer dictionary is not an integer");
"trailer", "/Size key in trailer dictionary is not an integer");
} }
} }
@ -940,11 +905,9 @@ QPDF::read_xrefTable(qpdf_offset_t xref_offset)
// Read the xref stream but disregard any return value // Read the xref stream but disregard any return value
// -- we'll use our trailer's /Prev key instead of the // -- we'll use our trailer's /Prev key instead of the
// xref stream's. // xref stream's.
(void)read_xrefStream( (void)read_xrefStream(cur_trailer.getKey("/XRefStm").getIntValue());
cur_trailer.getKey("/XRefStm").getIntValue());
} else { } else {
throw damagedPDF( throw damagedPDF("xref stream", xref_offset, "invalid /XRefStm");
"xref stream", xref_offset, "invalid /XRefStm");
} }
} }
} }
@ -957,8 +920,7 @@ QPDF::read_xrefTable(qpdf_offset_t xref_offset)
if (cur_trailer.hasKey("/Prev")) { if (cur_trailer.hasKey("/Prev")) {
if (!cur_trailer.getKey("/Prev").isInteger()) { if (!cur_trailer.getKey("/Prev").isInteger()) {
QTC::TC("qpdf", "QPDF trailer prev not integer"); QTC::TC("qpdf", "QPDF trailer prev not integer");
throw damagedPDF( throw damagedPDF("trailer", "/Prev key in trailer dictionary is not an integer");
"trailer", "/Prev key in trailer dictionary is not an integer");
} }
QTC::TC("qpdf", "QPDF prev key in trailer dictionary"); QTC::TC("qpdf", "QPDF prev key in trailer dictionary");
xref_offset = cur_trailer.getKey("/Prev").getIntValue(); xref_offset = cur_trailer.getKey("/Prev").getIntValue();
@ -977,13 +939,8 @@ QPDF::read_xrefStream(qpdf_offset_t xref_offset)
QPDFObjGen x_og; QPDFObjGen x_og;
QPDFObjectHandle xref_obj; QPDFObjectHandle xref_obj;
try { try {
xref_obj = readObjectAtOffset( xref_obj =
false, readObjectAtOffset(false, xref_offset, "xref stream", QPDFObjGen(0, 0), x_og, true);
xref_offset,
"xref stream",
QPDFObjGen(0, 0),
x_og,
true);
} catch (QPDFExc&) { } catch (QPDFExc&) {
// ignore -- report error below // ignore -- report error below
} }
@ -1008,12 +965,9 @@ QPDF::processXRefStream(qpdf_offset_t xref_offset, QPDFObjectHandle& xref_obj)
QPDFObjectHandle dict = xref_obj.getDict(); QPDFObjectHandle dict = xref_obj.getDict();
QPDFObjectHandle W_obj = dict.getKey("/W"); QPDFObjectHandle W_obj = dict.getKey("/W");
QPDFObjectHandle Index_obj = dict.getKey("/Index"); QPDFObjectHandle Index_obj = dict.getKey("/Index");
if (!(W_obj.isArray() && (W_obj.getArrayNItems() >= 3) && if (!(W_obj.isArray() && (W_obj.getArrayNItems() >= 3) && W_obj.getArrayItem(0).isInteger() &&
W_obj.getArrayItem(0).isInteger() && W_obj.getArrayItem(1).isInteger() && W_obj.getArrayItem(2).isInteger() &&
W_obj.getArrayItem(1).isInteger() && dict.getKey("/Size").isInteger() && (Index_obj.isArray() || Index_obj.isNull()))) {
W_obj.getArrayItem(2).isInteger() &&
dict.getKey("/Size").isInteger() &&
(Index_obj.isArray() || Index_obj.isNull()))) {
throw damagedPDF( throw damagedPDF(
"xref stream", "xref stream",
xref_offset, xref_offset,
@ -1035,12 +989,9 @@ QPDF::processXRefStream(qpdf_offset_t xref_offset, QPDFObjectHandle& xref_obj)
} }
if (entry_size == 0) { if (entry_size == 0) {
throw damagedPDF( throw damagedPDF(
"xref stream", "xref stream", xref_offset, "Cross-reference stream's /W indicates entry size of 0");
xref_offset,
"Cross-reference stream's /W indicates entry size of 0");
} }
unsigned long long max_num_entries = unsigned long long max_num_entries = static_cast<unsigned long long>(-1) / entry_size;
static_cast<unsigned long long>(-1) / entry_size;
std::vector<long long> indx; std::vector<long long> indx;
if (Index_obj.isArray()) { if (Index_obj.isArray()) {
@ -1059,8 +1010,8 @@ QPDF::processXRefStream(qpdf_offset_t xref_offset, QPDFObjectHandle& xref_obj)
throw damagedPDF( throw damagedPDF(
"xref stream", "xref stream",
xref_offset, xref_offset,
("Cross-reference stream's /Index's item " + ("Cross-reference stream's /Index's item " + std::to_string(i) +
std::to_string(i) + " is not an integer")); " is not an integer"));
} }
} }
QTC::TC("qpdf", "QPDF xref /Index is array", n_index == 2 ? 0 : 1); QTC::TC("qpdf", "QPDF xref /Index is array", n_index == 2 ? 0 : 1);
@ -1078,8 +1029,7 @@ QPDF::processXRefStream(qpdf_offset_t xref_offset, QPDFObjectHandle& xref_obj)
"xref stream", "xref stream",
xref_offset, xref_offset,
("Cross-reference stream claims to contain too many entries: " + ("Cross-reference stream claims to contain too many entries: " +
std::to_string(indx.at(i)) + " " + std::to_string(indx.at(i)) + " " + std::to_string(max_num_entries) + " " +
std::to_string(max_num_entries) + " " +
std::to_string(num_entries))); std::to_string(num_entries)));
} }
num_entries += toS(indx.at(i)); num_entries += toS(indx.at(i));
@ -1097,8 +1047,7 @@ QPDF::processXRefStream(qpdf_offset_t xref_offset, QPDFObjectHandle& xref_obj)
"xref stream", "xref stream",
xref_offset, xref_offset,
("Cross-reference stream data has the wrong size; expected = " + ("Cross-reference stream data has the wrong size; expected = " +
std::to_string(expected_size) + std::to_string(expected_size) + "; actual = " + std::to_string(actual_size)));
"; actual = " + std::to_string(actual_size)));
if (expected_size > actual_size) { if (expected_size > actual_size) {
throw x; throw x;
} else { } else {
@ -1137,8 +1086,7 @@ QPDF::processXRefStream(qpdf_offset_t xref_offset, QPDFObjectHandle& xref_obj)
// an uncompressed object record, in which case the generation // an uncompressed object record, in which case the generation
// number appears as the third field. // number appears as the third field.
int obj = toI(indx.at(cur_chunk)); int obj = toI(indx.at(cur_chunk));
if ((obj < 0) || if ((obj < 0) || ((std::numeric_limits<int>::max() - obj) < chunk_count)) {
((std::numeric_limits<int>::max() - obj) < chunk_count)) {
std::ostringstream msg; std::ostringstream msg;
msg.imbue(std::locale::classic()); msg.imbue(std::locale::classic());
msg << "adding " << chunk_count << " to " << obj msg << "adding " << chunk_count << " to " << obj
@ -1181,8 +1129,7 @@ QPDF::processXRefStream(qpdf_offset_t xref_offset, QPDFObjectHandle& xref_obj)
if (dict.hasKey("/Prev")) { if (dict.hasKey("/Prev")) {
if (!dict.getKey("/Prev").isInteger()) { if (!dict.getKey("/Prev").isInteger()) {
throw damagedPDF( throw damagedPDF(
"xref stream", "xref stream", "/Prev key in xref stream dictionary is not an integer");
"/Prev key in xref stream dictionary is not an integer");
} }
QTC::TC("qpdf", "QPDF prev key in xref stream dictionary"); QTC::TC("qpdf", "QPDF prev key in xref stream dictionary");
xref_offset = dict.getKey("/Prev").getIntValue(); xref_offset = dict.getKey("/Prev").getIntValue();
@ -1241,9 +1188,7 @@ QPDF::insertXrefEntry(int obj, int f0, qpdf_offset_t f1, int f2, bool overwrite)
break; break;
default: default:
throw damagedPDF( throw damagedPDF("xref stream", "unknown xref stream entry type " + std::to_string(f0));
"xref stream",
"unknown xref stream entry type " + std::to_string(f0));
break; break;
} }
} }
@ -1262,9 +1207,8 @@ QPDF::showXRefTable()
break; break;
case 2: case 2:
*m->log->getInfo() *m->log->getInfo() << "compressed; stream = " << entry.getObjStreamNumber()
<< "compressed; stream = " << entry.getObjStreamNumber() << ", index = " << entry.getObjStreamIndex();
<< ", index = " << entry.getObjStreamIndex();
break; break;
default: default:
@ -1337,8 +1281,7 @@ QPDF::getAllObjects()
} }
void void
QPDF::setLastObjectDescription( QPDF::setLastObjectDescription(std::string const& description, QPDFObjGen const& og)
std::string const& description, QPDFObjGen const& og)
{ {
m->last_object_description.clear(); m->last_object_description.clear();
if (!description.empty()) { if (!description.empty()) {
@ -1369,16 +1312,13 @@ QPDF::readObject(
decrypter_ph = std::make_shared<StringDecrypter>(this, og); decrypter_ph = std::make_shared<StringDecrypter>(this, og);
decrypter = decrypter_ph.get(); decrypter = decrypter_ph.get();
} }
auto object = auto object = QPDFParser(input, m->last_object_description, m->tokenizer, decrypter, this)
QPDFParser( .parse(empty, false);
input, m->last_object_description, m->tokenizer, decrypter, this)
.parse(empty, false);
if (empty) { if (empty) {
// Nothing in the PDF spec appears to allow empty objects, but // Nothing in the PDF spec appears to allow empty objects, but
// they have been encountered in actual PDF files and Adobe // they have been encountered in actual PDF files and Adobe
// Reader appears to ignore them. // Reader appears to ignore them.
warn(damagedPDF( warn(damagedPDF(input, input->getLastOffset(), "empty object treated as null"));
input, input->getLastOffset(), "empty object treated as null"));
} else if (object.isDictionary() && (!in_object_stream)) { } else if (object.isDictionary() && (!in_object_stream)) {
// check for stream // check for stream
qpdf_offset_t cur_offset = input->tell(); qpdf_offset_t cur_offset = input->tell();
@ -1428,9 +1368,7 @@ QPDF::readObject(
} }
} else if (QUtil::is_space(ch)) { } else if (QUtil::is_space(ch)) {
warn(damagedPDF( warn(damagedPDF(
input, input, input->tell(), "stream keyword followed by extraneous whitespace"));
input->tell(),
"stream keyword followed by extraneous whitespace"));
done = false; done = false;
} else { } else {
QTC::TC("qpdf", "QPDF stream without newline"); QTC::TC("qpdf", "QPDF stream without newline");
@ -1450,13 +1388,11 @@ QPDF::readObject(
size_t length = 0; size_t length = 0;
try { try {
std::map<std::string, QPDFObjectHandle> dict = std::map<std::string, QPDFObjectHandle> dict = object.getDictAsMap();
object.getDictAsMap();
if (dict.count("/Length") == 0) { if (dict.count("/Length") == 0) {
QTC::TC("qpdf", "QPDF stream without length"); QTC::TC("qpdf", "QPDF stream without length");
throw damagedPDF( throw damagedPDF(input, offset, "stream dictionary lacks /Length key");
input, offset, "stream dictionary lacks /Length key");
} }
QPDFObjectHandle length_obj = dict["/Length"]; QPDFObjectHandle length_obj = dict["/Length"];
@ -1475,8 +1411,7 @@ QPDF::readObject(
input->seek(toO(length), SEEK_CUR); input->seek(toO(length), SEEK_CUR);
if (!readToken(input).isWord("endstream")) { if (!readToken(input).isWord("endstream")) {
QTC::TC("qpdf", "QPDF missing endstream"); QTC::TC("qpdf", "QPDF missing endstream");
throw damagedPDF( throw damagedPDF(input, input->getLastOffset(), "expected endstream");
input, input->getLastOffset(), "expected endstream");
} }
} catch (QPDFExc& e) { } catch (QPDFExc& e) {
if (m->attempt_recovery) { if (m->attempt_recovery) {
@ -1486,9 +1421,7 @@ QPDF::readObject(
throw; throw;
} }
} }
object = newIndirect( object = newIndirect(og, QPDF_Stream::create(this, og, object, stream_offset, length));
og,
QPDF_Stream::create(this, og, object, stream_offset, length));
} else { } else {
input->seek(cur_offset, SEEK_SET); input->seek(cur_offset, SEEK_SET);
} }
@ -1514,14 +1447,11 @@ QPDF::findEndstream()
size_t size_t
QPDF::recoverStreamLength( QPDF::recoverStreamLength(
std::shared_ptr<InputSource> input, std::shared_ptr<InputSource> input, QPDFObjGen const& og, qpdf_offset_t stream_offset)
QPDFObjGen const& og,
qpdf_offset_t stream_offset)
{ {
// Try to reconstruct stream length by looking for // Try to reconstruct stream length by looking for
// endstream or endobj // endstream or endobj
warn(damagedPDF( warn(damagedPDF(input, stream_offset, "attempting to recover stream length"));
input, stream_offset, "attempting to recover stream length"));
PatternFinder ef(*this, &QPDF::findEndstream); PatternFinder ef(*this, &QPDF::findEndstream);
size_t length = 0; size_t length = 0;
@ -1544,8 +1474,7 @@ QPDF::recoverStreamLength(
if (entry.getType() == 1) { if (entry.getType() == 1) {
qpdf_offset_t obj_offset = entry.getOffset(); qpdf_offset_t obj_offset = entry.getOffset();
if ((obj_offset > stream_offset) && if ((obj_offset > stream_offset) &&
((this_obj_offset == 0) || ((this_obj_offset == 0) || (this_obj_offset > obj_offset))) {
(this_obj_offset > obj_offset))) {
this_obj_offset = obj_offset; this_obj_offset = obj_offset;
this_og = iter.first; this_og = iter.first;
} }
@ -1562,14 +1491,10 @@ QPDF::recoverStreamLength(
if (length == 0) { if (length == 0) {
warn(damagedPDF( warn(damagedPDF(
input, input, stream_offset, "unable to recover stream data; treating stream as empty"));
stream_offset,
"unable to recover stream data; treating stream as empty"));
} else { } else {
warn(damagedPDF( warn(
input, damagedPDF(input, stream_offset, "recovered stream length: " + std::to_string(length)));
stream_offset,
"recovered stream length: " + std::to_string(length)));
} }
QTC::TC("qpdf", "QPDF recovered stream length"); QTC::TC("qpdf", "QPDF recovered stream length");
@ -1579,8 +1504,7 @@ QPDF::recoverStreamLength(
QPDFTokenizer::Token QPDFTokenizer::Token
QPDF::readToken(std::shared_ptr<InputSource> input, size_t max_len) QPDF::readToken(std::shared_ptr<InputSource> input, size_t max_len)
{ {
return m->tokenizer.readToken( return m->tokenizer.readToken(input, m->last_object_description, true, max_len);
input, m->last_object_description, true, max_len);
} }
QPDFObjectHandle QPDFObjectHandle
@ -1650,8 +1574,7 @@ QPDF::readObjectAtOffset(
} }
if (check_og && (exp_og != og)) { if (check_og && (exp_og != og)) {
QTC::TC("qpdf", "QPDF err wrong objid/generation"); QTC::TC("qpdf", "QPDF err wrong objid/generation");
QPDFExc e = QPDFExc e = damagedPDF(offset, "expected " + exp_og.unparse(' ') + " obj");
damagedPDF(offset, "expected " + exp_og.unparse(' ') + " obj");
if (try_recovery) { if (try_recovery) {
// Will be retried below // Will be retried below
throw e; throw e;
@ -1665,11 +1588,10 @@ QPDF::readObjectAtOffset(
if (try_recovery) { if (try_recovery) {
// Try again after reconstructing xref table // Try again after reconstructing xref table
reconstruct_xref(e); reconstruct_xref(e);
if (m->xref_table.count(exp_og) && if (m->xref_table.count(exp_og) && (m->xref_table[exp_og].getType() == 1)) {
(m->xref_table[exp_og].getType() == 1)) {
qpdf_offset_t new_offset = m->xref_table[exp_og].getOffset(); qpdf_offset_t new_offset = m->xref_table[exp_og].getOffset();
QPDFObjectHandle result = readObjectAtOffset( QPDFObjectHandle result =
false, new_offset, description, exp_og, og, false); readObjectAtOffset(false, new_offset, description, exp_og, og, false);
QTC::TC("qpdf", "QPDF recovered in readObjectAtOffset"); QTC::TC("qpdf", "QPDF recovered in readObjectAtOffset");
return result; return result;
} else { } else {
@ -1777,8 +1699,7 @@ QPDF::resolve(QPDFObjGen og)
// indirectly in some key that has to be resolved during // indirectly in some key that has to be resolved during
// object parsing, such as stream length. // object parsing, such as stream length.
QTC::TC("qpdf", "QPDF recursion loop in resolve"); QTC::TC("qpdf", "QPDF recursion loop in resolve");
warn(damagedPDF( warn(damagedPDF("", "loop detected resolving object " + og.unparse(' ')));
"", "loop detected resolving object " + og.unparse(' ')));
updateCache(og, QPDF_Null::create(), -1, -1); updateCache(og, QPDF_Null::create(), -1, -1);
return; return;
} }
@ -1793,8 +1714,7 @@ QPDF::resolve(QPDFObjGen og)
qpdf_offset_t offset = entry.getOffset(); qpdf_offset_t offset = entry.getOffset();
// Object stored in cache by readObjectAtOffset // Object stored in cache by readObjectAtOffset
QPDFObjGen a_og; QPDFObjGen a_og;
QPDFObjectHandle oh = QPDFObjectHandle oh = readObjectAtOffset(true, offset, "", og, a_og, false);
readObjectAtOffset(true, offset, "", og, a_og, false);
} }
break; break;
@ -1804,19 +1724,13 @@ QPDF::resolve(QPDFObjGen og)
default: default:
throw damagedPDF( throw damagedPDF(
"", "", 0, ("object " + og.unparse('/') + " has unexpected xref entry type"));
0,
("object " + og.unparse('/') +
" has unexpected xref entry type"));
} }
} catch (QPDFExc& e) { } catch (QPDFExc& e) {
warn(e); warn(e);
} catch (std::exception& e) { } catch (std::exception& e) {
warn(damagedPDF( warn(damagedPDF(
"", "", 0, ("object " + og.unparse('/') + ": error reading object: " + e.what())));
0,
("object " + og.unparse('/') +
": error reading object: " + e.what())));
} }
} }
@ -1841,8 +1755,7 @@ QPDF::resolveObjectsInStream(int obj_stream_number)
QPDFObjectHandle obj_stream = getObjectByID(obj_stream_number, 0); QPDFObjectHandle obj_stream = getObjectByID(obj_stream_number, 0);
if (!obj_stream.isStream()) { if (!obj_stream.isStream()) {
throw damagedPDF( throw damagedPDF(
"supposed object stream " + std::to_string(obj_stream_number) + "supposed object stream " + std::to_string(obj_stream_number) + " is not a stream");
" is not a stream");
} }
// For linearization data in the object, use the data from the // For linearization data in the object, use the data from the
@ -1855,14 +1768,12 @@ QPDF::resolveObjectsInStream(int obj_stream_number)
if (!dict.isDictionaryOfType("/ObjStm")) { if (!dict.isDictionaryOfType("/ObjStm")) {
QTC::TC("qpdf", "QPDF ERR object stream with wrong type"); QTC::TC("qpdf", "QPDF ERR object stream with wrong type");
warn(damagedPDF( warn(damagedPDF(
"supposed object stream " + std::to_string(obj_stream_number) + "supposed object stream " + std::to_string(obj_stream_number) + " has wrong type"));
" has wrong type"));
} }
if (!(dict.getKey("/N").isInteger() && dict.getKey("/First").isInteger())) { if (!(dict.getKey("/N").isInteger() && dict.getKey("/First").isInteger())) {
throw damagedPDF( throw damagedPDF(
("object stream " + std::to_string(obj_stream_number) + ("object stream " + std::to_string(obj_stream_number) + " has incorrect keys"));
" has incorrect keys"));
} }
int n = dict.getKey("/N").getIntValueAsInt(); int n = dict.getKey("/N").getIntValueAsInt();
@ -1874,8 +1785,7 @@ QPDF::resolveObjectsInStream(int obj_stream_number)
auto input = std::shared_ptr<InputSource>( auto input = std::shared_ptr<InputSource>(
// line-break // line-break
new BufferInputSource( new BufferInputSource(
(m->file->getName() + " object stream " + (m->file->getName() + " object stream " + std::to_string(obj_stream_number)),
std::to_string(obj_stream_number)),
bp.get())); bp.get()));
for (int i = 0; i < n; ++i) { for (int i = 0; i < n; ++i) {
@ -1902,8 +1812,7 @@ QPDF::resolveObjectsInStream(int obj_stream_number)
for (auto const& iter: offsets) { for (auto const& iter: offsets) {
QPDFObjGen og(iter.first, 0); QPDFObjGen og(iter.first, 0);
QPDFXRefEntry const& entry = m->xref_table[og]; QPDFXRefEntry const& entry = m->xref_table[og];
if ((entry.getType() == 2) && if ((entry.getType() == 2) && (entry.getObjStreamNumber() == obj_stream_number)) {
(entry.getObjStreamNumber() == obj_stream_number)) {
int offset = iter.second; int offset = iter.second;
input->seek(offset, SEEK_SET); input->seek(offset, SEEK_SET);
QPDFObjectHandle oh = readObject(input, "", og, true); QPDFObjectHandle oh = readObject(input, "", og, true);
@ -1956,8 +1865,7 @@ QPDF::nextObjGen()
{ {
int max_objid = toI(getObjectCount()); int max_objid = toI(getObjectCount());
if (max_objid == std::numeric_limits<int>::max()) { if (max_objid == std::numeric_limits<int>::max()) {
throw std::range_error( throw std::range_error("max object id is too high to create new objects");
"max object id is too high to create new objects");
} }
return QPDFObjGen(max_objid + 1, 0); return QPDFObjGen(max_objid + 1, 0);
} }
@ -1974,8 +1882,7 @@ QPDFObjectHandle
QPDF::makeIndirectObject(QPDFObjectHandle oh) QPDF::makeIndirectObject(QPDFObjectHandle oh)
{ {
if (!oh.isInitialized()) { if (!oh.isInitialized()) {
throw std::logic_error( throw std::logic_error("attempted to make an uninitialized QPDFObjectHandle indirect");
"attempted to make an uninitialized QPDFObjectHandle indirect");
} }
return makeIndirectFromQPDFObject(oh.getObj()); return makeIndirectFromQPDFObject(oh.getObj());
} }
@ -1989,16 +1896,15 @@ QPDF::newReserved()
QPDFObjectHandle QPDFObjectHandle
QPDF::newStream() QPDF::newStream()
{ {
return makeIndirectFromQPDFObject(QPDF_Stream::create( return makeIndirectFromQPDFObject(
this, nextObjGen(), QPDFObjectHandle::newDictionary(), 0, 0)); QPDF_Stream::create(this, nextObjGen(), QPDFObjectHandle::newDictionary(), 0, 0));
} }
QPDFObjectHandle QPDFObjectHandle
QPDF::newStream(std::shared_ptr<Buffer> data) QPDF::newStream(std::shared_ptr<Buffer> data)
{ {
auto result = newStream(); auto result = newStream();
result.replaceStreamData( result.replaceStreamData(data, QPDFObjectHandle::newNull(), QPDFObjectHandle::newNull());
data, QPDFObjectHandle::newNull(), QPDFObjectHandle::newNull());
return result; return result;
} }
@ -2006,8 +1912,7 @@ QPDFObjectHandle
QPDF::newStream(std::string const& data) QPDF::newStream(std::string const& data)
{ {
auto result = newStream(); auto result = newStream();
result.replaceStreamData( result.replaceStreamData(data, QPDFObjectHandle::newNull(), QPDFObjectHandle::newNull());
data, QPDFObjectHandle::newNull(), QPDFObjectHandle::newNull());
return result; return result;
} }
@ -2025,8 +1930,7 @@ QPDF::reserveObjectIfNotExists(QPDFObjGen const& og)
QPDFObjectHandle QPDFObjectHandle
QPDF::reserveStream(QPDFObjGen const& og) QPDF::reserveStream(QPDFObjGen const& og)
{ {
return { return {QPDF_Stream::create(this, og, QPDFObjectHandle::newDictionary(), 0, 0)};
QPDF_Stream::create(this, og, QPDFObjectHandle::newDictionary(), 0, 0)};
} }
QPDFObjectHandle QPDFObjectHandle
@ -2069,8 +1973,7 @@ QPDF::replaceObject(QPDFObjGen const& og, QPDFObjectHandle oh)
{ {
if (oh.isIndirect() || !oh.isInitialized()) { if (oh.isIndirect() || !oh.isInitialized()) {
QTC::TC("qpdf", "QPDF replaceObject called with indirect object"); QTC::TC("qpdf", "QPDF replaceObject called with indirect object");
throw std::logic_error( throw std::logic_error("QPDF::replaceObject called with indirect object handle");
"QPDF::replaceObject called with indirect object handle");
} }
updateCache(og, oh.getObj(), -1, -1); updateCache(og, oh.getObj(), -1, -1);
} }
@ -2132,14 +2035,12 @@ QPDF::copyForeignObject(QPDFObjectHandle foreign)
// the intention is to not update the pages tree. // the intention is to not update the pages tree.
if (!foreign.isIndirect()) { if (!foreign.isIndirect()) {
QTC::TC("qpdf", "QPDF copyForeign direct"); QTC::TC("qpdf", "QPDF copyForeign direct");
throw std::logic_error( throw std::logic_error("QPDF::copyForeign called with direct object handle");
"QPDF::copyForeign called with direct object handle");
} }
QPDF& other = foreign.getQPDF(); QPDF& other = foreign.getQPDF();
if (&other == this) { if (&other == this) {
QTC::TC("qpdf", "QPDF copyForeign not foreign"); QTC::TC("qpdf", "QPDF copyForeign not foreign");
throw std::logic_error( throw std::logic_error("QPDF::copyForeign called with object from this QPDF");
"QPDF::copyForeign called with object from this QPDF");
} }
ObjCopier& obj_copier = m->object_copiers[other.m->unique_id]; ObjCopier& obj_copier = m->object_copiers[other.m->unique_id];
@ -2163,8 +2064,7 @@ QPDF::copyForeignObject(QPDFObjectHandle foreign)
// Copy any new objects and replace the reservations. // Copy any new objects and replace the reservations.
for (auto& to_copy: obj_copier.to_copy) { for (auto& to_copy: obj_copier.to_copy) {
QPDFObjectHandle copy = QPDFObjectHandle copy = replaceForeignIndirectObjects(to_copy, obj_copier, true);
replaceForeignIndirectObjects(to_copy, obj_copier, true);
if (!to_copy.isStream()) { if (!to_copy.isStream()) {
QPDFObjGen og(to_copy.getObjGen()); QPDFObjGen og(to_copy.getObjGen());
replaceReserved(obj_copier.object_map[og], copy); replaceReserved(obj_copier.object_map[og], copy);
@ -2180,8 +2080,7 @@ QPDF::reserveObjects(QPDFObjectHandle foreign, ObjCopier& obj_copier, bool top)
{ {
auto foreign_tc = foreign.getTypeCode(); auto foreign_tc = foreign.getTypeCode();
if (foreign_tc == ::ot_reserved) { if (foreign_tc == ::ot_reserved) {
throw std::logic_error( throw std::logic_error("QPDF: attempting to copy a foreign reserved object");
"QPDF: attempting to copy a foreign reserved object");
} }
if (foreign.isPagesObject()) { if (foreign.isPagesObject()) {
@ -2209,8 +2108,7 @@ QPDF::reserveObjects(QPDFObjectHandle foreign, ObjCopier& obj_copier, bool top)
QTC::TC("qpdf", "QPDF copy indirect"); QTC::TC("qpdf", "QPDF copy indirect");
if (obj_copier.object_map.count(foreign_og) == 0) { if (obj_copier.object_map.count(foreign_og) == 0) {
obj_copier.to_copy.push_back(foreign); obj_copier.to_copy.push_back(foreign);
obj_copier.object_map[foreign_og] = obj_copier.object_map[foreign_og] = foreign.isStream() ? newStream() : newReserved();
foreign.isStream() ? newStream() : newReserved();
} }
} }
@ -2234,8 +2132,7 @@ QPDF::reserveObjects(QPDFObjectHandle foreign, ObjCopier& obj_copier, bool top)
} }
QPDFObjectHandle QPDFObjectHandle
QPDF::replaceForeignIndirectObjects( QPDF::replaceForeignIndirectObjects(QPDFObjectHandle foreign, ObjCopier& obj_copier, bool top)
QPDFObjectHandle foreign, ObjCopier& obj_copier, bool top)
{ {
auto foreign_tc = foreign.getTypeCode(); auto foreign_tc = foreign.getTypeCode();
QPDFObjectHandle result; QPDFObjectHandle result;
@ -2257,8 +2154,7 @@ QPDF::replaceForeignIndirectObjects(
for (int i = 0; i < n; ++i) { for (int i = 0; i < n; ++i) {
result.appendItem( result.appendItem(
// line-break // line-break
replaceForeignIndirectObjects( replaceForeignIndirectObjects(foreign.getArrayItem(i), obj_copier, false));
foreign.getArrayItem(i), obj_copier, false));
} }
} else if (foreign_tc == ::ot_dictionary) { } else if (foreign_tc == ::ot_dictionary) {
QTC::TC("qpdf", "QPDF replace dictionary"); QTC::TC("qpdf", "QPDF replace dictionary");
@ -2266,9 +2162,7 @@ QPDF::replaceForeignIndirectObjects(
std::set<std::string> keys = foreign.getKeys(); std::set<std::string> keys = foreign.getKeys();
for (auto const& iter: keys) { for (auto const& iter: keys) {
result.replaceKey( result.replaceKey(
iter, iter, replaceForeignIndirectObjects(foreign.getKey(iter), obj_copier, false));
replaceForeignIndirectObjects(
foreign.getKey(iter), obj_copier, false));
} }
} else if (foreign_tc == ::ot_stream) { } else if (foreign_tc == ::ot_stream) {
QTC::TC("qpdf", "QPDF replace stream"); QTC::TC("qpdf", "QPDF replace stream");
@ -2279,9 +2173,7 @@ QPDF::replaceForeignIndirectObjects(
std::set<std::string> keys = old_dict.getKeys(); std::set<std::string> keys = old_dict.getKeys();
for (auto const& iter: keys) { for (auto const& iter: keys) {
dict.replaceKey( dict.replaceKey(
iter, iter, replaceForeignIndirectObjects(old_dict.getKey(iter), obj_copier, false));
replaceForeignIndirectObjects(
old_dict.getKey(iter), obj_copier, false));
} }
copyStreamData(result, foreign); copyStreamData(result, foreign);
} else { } else {
@ -2309,8 +2201,7 @@ QPDF::copyStreamData(QPDFObjectHandle result, QPDFObjectHandle foreign)
if (m->copied_stream_data_provider == nullptr) { if (m->copied_stream_data_provider == nullptr) {
m->copied_stream_data_provider = new CopiedStreamDataProvider(*this); m->copied_stream_data_provider = new CopiedStreamDataProvider(*this);
m->copied_streams = m->copied_streams =
std::shared_ptr<QPDFObjectHandle::StreamDataProvider>( std::shared_ptr<QPDFObjectHandle::StreamDataProvider>(m->copied_stream_data_provider);
m->copied_stream_data_provider);
} }
QPDFObjGen local_og(result.getObjGen()); QPDFObjGen local_og(result.getObjGen());
// Copy information from the foreign stream so we can pipe its // Copy information from the foreign stream so we can pipe its
@ -2325,8 +2216,7 @@ QPDF::copyStreamData(QPDFObjectHandle result, QPDFObjectHandle foreign)
" stream object from foreign stream"); " stream object from foreign stream");
} }
std::shared_ptr<Buffer> stream_buffer = stream->getStreamDataBuffer(); std::shared_ptr<Buffer> stream_buffer = stream->getStreamDataBuffer();
if ((foreign_stream_qpdf.m->immediate_copy_from) && if ((foreign_stream_qpdf.m->immediate_copy_from) && (stream_buffer == nullptr)) {
(stream_buffer == nullptr)) {
// Pull the stream data into a buffer before attempting // Pull the stream data into a buffer before attempting
// the copy operation. Do it on the source stream so that // the copy operation. Do it on the source stream so that
// if the source stream is copied multiple times, we don't // if the source stream is copied multiple times, we don't
@ -2347,12 +2237,9 @@ QPDF::copyStreamData(QPDFObjectHandle result, QPDFObjectHandle foreign)
} else if (stream_provider.get()) { } else if (stream_provider.get()) {
// In this case, the remote stream's QPDF must stay in scope. // In this case, the remote stream's QPDF must stay in scope.
QTC::TC("qpdf", "QPDF copy foreign stream with provider"); QTC::TC("qpdf", "QPDF copy foreign stream with provider");
m->copied_stream_data_provider->registerForeignStream( m->copied_stream_data_provider->registerForeignStream(local_og, foreign);
local_og, foreign);
result.replaceStreamData( result.replaceStreamData(
m->copied_streams, m->copied_streams, dict.getKey("/Filter"), dict.getKey("/DecodeParms"));
dict.getKey("/Filter"),
dict.getKey("/DecodeParms"));
} else { } else {
auto foreign_stream_data = std::make_shared<ForeignStreamData>( auto foreign_stream_data = std::make_shared<ForeignStreamData>(
foreign_stream_qpdf.m->encp, foreign_stream_qpdf.m->encp,
@ -2361,20 +2248,16 @@ QPDF::copyStreamData(QPDFObjectHandle result, QPDFObjectHandle foreign)
stream->getParsedOffset(), stream->getParsedOffset(),
stream->getLength(), stream->getLength(),
dict); dict);
m->copied_stream_data_provider->registerForeignStream( m->copied_stream_data_provider->registerForeignStream(local_og, foreign_stream_data);
local_og, foreign_stream_data);
result.replaceStreamData( result.replaceStreamData(
m->copied_streams, m->copied_streams, dict.getKey("/Filter"), dict.getKey("/DecodeParms"));
dict.getKey("/Filter"),
dict.getKey("/DecodeParms"));
} }
} }
void void
QPDF::swapObjects(int objid1, int generation1, int objid2, int generation2) QPDF::swapObjects(int objid1, int generation1, int objid2, int generation2)
{ {
swapObjects( swapObjects(QPDFObjGen(objid1, generation1), QPDFObjGen(objid2, generation2));
QPDFObjGen(objid1, generation1), QPDFObjGen(objid2, generation2));
} }
void void
@ -2519,8 +2402,7 @@ QPDF::getCompressibleObjGens()
if (og == encryption_dict_og) { if (og == encryption_dict_og) {
QTC::TC("qpdf", "QPDF exclude encryption dictionary"); QTC::TC("qpdf", "QPDF exclude encryption dictionary");
} else if (!(obj.isStream() || } else if (!(obj.isStream() ||
(obj.isDictionaryOfType("/Sig") && (obj.isDictionaryOfType("/Sig") && obj.hasKey("/ByteRange") &&
obj.hasKey("/ByteRange") &&
obj.hasKey("/Contents")))) { obj.hasKey("/Contents")))) {
result.push_back(og); result.push_back(og);
} }
@ -2571,8 +2453,7 @@ QPDF::pipeStreamData(
{ {
std::vector<std::shared_ptr<Pipeline>> to_delete; std::vector<std::shared_ptr<Pipeline>> to_delete;
if (encp->encrypted) { if (encp->encrypted) {
decryptStream( decryptStream(encp, file, qpdf_for_warning, pipeline, og, stream_dict, to_delete);
encp, file, qpdf_for_warning, pipeline, og, stream_dict, to_delete);
} }
bool success = false; bool success = false;
@ -2584,10 +2465,7 @@ QPDF::pipeStreamData(
size_t len = file->read(buf, to_read); size_t len = file->read(buf, to_read);
if (len == 0) { if (len == 0) {
throw damagedPDF( throw damagedPDF(
file, file, "", file->getLastOffset(), "unexpected EOF reading stream data");
"",
file->getLastOffset(),
"unexpected EOF reading stream data");
} }
length -= len; length -= len;
pipeline->write(buf, len); pipeline->write(buf, len);
@ -2607,8 +2485,8 @@ QPDF::pipeStreamData(
file, file,
"", "",
file->getLastOffset(), file->getLastOffset(),
("error decoding stream data for object " + ("error decoding stream data for object " + og.unparse(' ') + ": " +
og.unparse(' ') + ": " + e.what()))); e.what())));
if (will_retry) { if (will_retry) {
qpdf_for_warning.warn( qpdf_for_warning.warn(
// line-break // line-break
@ -2694,17 +2572,14 @@ QPDF::damagedPDF(
qpdf_offset_t offset, qpdf_offset_t offset,
std::string const& message) std::string const& message)
{ {
return QPDFExc( return QPDFExc(qpdf_e_damaged_pdf, input->getName(), object, offset, message);
qpdf_e_damaged_pdf, input->getName(), object, offset, message);
} }
// Return an exception of type qpdf_e_damaged_pdf. The object is taken from // Return an exception of type qpdf_e_damaged_pdf. The object is taken from
// m->last_object_description. // m->last_object_description.
QPDFExc QPDFExc
QPDF::damagedPDF( QPDF::damagedPDF(
std::shared_ptr<InputSource> const& input, std::shared_ptr<InputSource> const& input, qpdf_offset_t offset, std::string const& message)
qpdf_offset_t offset,
std::string const& message)
{ {
return damagedPDF(input, m->last_object_description, offset, message); return damagedPDF(input, m->last_object_description, offset, message);
} }
@ -2712,11 +2587,9 @@ QPDF::damagedPDF(
// Return an exception of type qpdf_e_damaged_pdf. The filename is taken from // Return an exception of type qpdf_e_damaged_pdf. The filename is taken from
// m->file. // m->file.
QPDFExc QPDFExc
QPDF::damagedPDF( QPDF::damagedPDF(std::string const& object, qpdf_offset_t offset, std::string const& message)
std::string const& object, qpdf_offset_t offset, std::string const& message)
{ {
return QPDFExc( return QPDFExc(qpdf_e_damaged_pdf, m->file->getName(), object, offset, message);
qpdf_e_damaged_pdf, m->file->getName(), object, offset, message);
} }
// Return an exception of type qpdf_e_damaged_pdf. The filename is taken from // Return an exception of type qpdf_e_damaged_pdf. The filename is taken from
@ -2741,8 +2614,7 @@ QPDF::damagedPDF(qpdf_offset_t offset, std::string const& message)
QPDFExc QPDFExc
QPDF::damagedPDF(std::string const& message) QPDF::damagedPDF(std::string const& message)
{ {
return damagedPDF( return damagedPDF(m->last_object_description, m->file->getLastOffset(), message);
m->last_object_description, m->file->getLastOffset(), message);
} }
bool bool

View File

@ -41,8 +41,7 @@ QPDFAcroFormDocumentHelper::getOrCreateAcroForm()
auto acroform = this->qpdf.getRoot().getKey("/AcroForm"); auto acroform = this->qpdf.getRoot().getKey("/AcroForm");
if (!acroform.isDictionary()) { if (!acroform.isDictionary()) {
acroform = this->qpdf.getRoot().replaceKeyAndGetNew( acroform = this->qpdf.getRoot().replaceKeyAndGetNew(
"/AcroForm", "/AcroForm", this->qpdf.makeIndirectObject(QPDFObjectHandle::newDictionary()));
this->qpdf.makeIndirectObject(QPDFObjectHandle::newDictionary()));
} }
return acroform; return acroform;
} }
@ -53,24 +52,20 @@ QPDFAcroFormDocumentHelper::addFormField(QPDFFormFieldObjectHelper ff)
auto acroform = getOrCreateAcroForm(); auto acroform = getOrCreateAcroForm();
auto fields = acroform.getKey("/Fields"); auto fields = acroform.getKey("/Fields");
if (!fields.isArray()) { if (!fields.isArray()) {
fields = acroform.replaceKeyAndGetNew( fields = acroform.replaceKeyAndGetNew("/Fields", QPDFObjectHandle::newArray());
"/Fields", QPDFObjectHandle::newArray());
} }
fields.appendItem(ff.getObjectHandle()); fields.appendItem(ff.getObjectHandle());
QPDFObjGen::set visited; QPDFObjGen::set visited;
traverseField( traverseField(ff.getObjectHandle(), QPDFObjectHandle::newNull(), 0, visited);
ff.getObjectHandle(), QPDFObjectHandle::newNull(), 0, visited);
} }
void void
QPDFAcroFormDocumentHelper::addAndRenameFormFields( QPDFAcroFormDocumentHelper::addAndRenameFormFields(std::vector<QPDFObjectHandle> fields)
std::vector<QPDFObjectHandle> fields)
{ {
analyze(); analyze();
std::map<std::string, std::string> renames; std::map<std::string, std::string> renames;
QPDFObjGen::set seen; QPDFObjGen::set seen;
for (std::list<QPDFObjectHandle> queue{fields.begin(), fields.end()}; for (std::list<QPDFObjectHandle> queue{fields.begin(), fields.end()}; !queue.empty();
!queue.empty();
queue.pop_front()) { queue.pop_front()) {
auto& obj = queue.front(); auto& obj = queue.front();
if (seen.add(obj)) { if (seen.add(obj)) {
@ -90,8 +85,7 @@ QPDFAcroFormDocumentHelper::addAndRenameFormFields(
// at the end of the fully qualified name, appending to /T // at the end of the fully qualified name, appending to /T
// has the effect of appending the same thing to the fully // has the effect of appending the same thing to the fully
// qualified name. // qualified name.
std::string old_name = std::string old_name = QPDFFormFieldObjectHelper(obj).getFullyQualifiedName();
QPDFFormFieldObjectHelper(obj).getFullyQualifiedName();
if (renames.count(old_name) == 0) { if (renames.count(old_name) == 0) {
std::string new_name = old_name; std::string new_name = old_name;
int suffix = 0; int suffix = 0;
@ -120,8 +114,7 @@ QPDFAcroFormDocumentHelper::addAndRenameFormFields(
} }
void void
QPDFAcroFormDocumentHelper::removeFormFields( QPDFAcroFormDocumentHelper::removeFormFields(std::set<QPDFObjGen> const& to_remove)
std::set<QPDFObjGen> const& to_remove)
{ {
auto acroform = this->qpdf.getRoot().getKey("/AcroForm"); auto acroform = this->qpdf.getRoot().getKey("/AcroForm");
if (!acroform.isDictionary()) { if (!acroform.isDictionary()) {
@ -162,8 +155,7 @@ QPDFAcroFormDocumentHelper::removeFormFields(
} }
void void
QPDFAcroFormDocumentHelper::setFormFieldName( QPDFAcroFormDocumentHelper::setFormFieldName(QPDFFormFieldObjectHelper ff, std::string const& name)
QPDFFormFieldObjectHelper ff, std::string const& name)
{ {
ff.setFieldAttribute("/T", name); ff.setFieldAttribute("/T", name);
QPDFObjGen::set visited; QPDFObjGen::set visited;
@ -257,8 +249,7 @@ QPDFAcroFormDocumentHelper::analyze()
QPDFObjectHandle fields = acroform.getKey("/Fields"); QPDFObjectHandle fields = acroform.getKey("/Fields");
if (!fields.isArray()) { if (!fields.isArray()) {
QTC::TC("qpdf", "QPDFAcroFormDocumentHelper fields not array"); QTC::TC("qpdf", "QPDFAcroFormDocumentHelper fields not array");
acroform.warnIfPossible( acroform.warnIfPossible("/Fields key of /AcroForm dictionary is not an array; ignoring");
"/Fields key of /AcroForm dictionary is not an array; ignoring");
fields = QPDFObjectHandle::newArray(); fields = QPDFObjectHandle::newArray();
} }
@ -294,12 +285,10 @@ QPDFAcroFormDocumentHelper::analyze()
// adding a self-contained annotation (merged with the // adding a self-contained annotation (merged with the
// field dictionary) to the page's /Annots array and // field dictionary) to the page's /Annots array and
// forgetting to also put it in /AcroForm. // forgetting to also put it in /AcroForm.
annot.warnIfPossible( annot.warnIfPossible("this widget annotation is not"
"this widget annotation is not" " reachable from /AcroForm in the document catalog");
" reachable from /AcroForm in the document catalog");
m->annotation_to_field[og] = QPDFFormFieldObjectHelper(annot); m->annotation_to_field[og] = QPDFFormFieldObjectHelper(annot);
m->field_to_annotations[og].push_back( m->field_to_annotations[og].push_back(QPDFAnnotationObjectHelper(annot));
QPDFAnnotationObjectHelper(annot));
} }
} }
} }
@ -307,10 +296,7 @@ QPDFAcroFormDocumentHelper::analyze()
void void
QPDFAcroFormDocumentHelper::traverseField( QPDFAcroFormDocumentHelper::traverseField(
QPDFObjectHandle field, QPDFObjectHandle field, QPDFObjectHandle parent, int depth, QPDFObjGen::set& visited)
QPDFObjectHandle parent,
int depth,
QPDFObjGen::set& visited)
{ {
if (depth > 100) { if (depth > 100) {
// Arbitrarily cut off recursion at a fixed depth to avoid // Arbitrarily cut off recursion at a fixed depth to avoid
@ -319,16 +305,14 @@ QPDFAcroFormDocumentHelper::traverseField(
} }
if (!field.isIndirect()) { if (!field.isIndirect()) {
QTC::TC("qpdf", "QPDFAcroFormDocumentHelper direct field"); QTC::TC("qpdf", "QPDFAcroFormDocumentHelper direct field");
field.warnIfPossible( field.warnIfPossible("encountered a direct object as a field or annotation while"
"encountered a direct object as a field or annotation while" " traversing /AcroForm; ignoring field or annotation");
" traversing /AcroForm; ignoring field or annotation");
return; return;
} }
if (!field.isDictionary()) { if (!field.isDictionary()) {
QTC::TC("qpdf", "QPDFAcroFormDocumentHelper non-dictionary field"); QTC::TC("qpdf", "QPDFAcroFormDocumentHelper non-dictionary field");
field.warnIfPossible( field.warnIfPossible("encountered a non-dictionary as a field or annotation while"
"encountered a non-dictionary as a field or annotation while" " traversing /AcroForm; ignoring field or annotation");
" traversing /AcroForm; ignoring field or annotation");
return; return;
} }
QPDFObjGen og(field.getObjGen()); QPDFObjGen og(field.getObjGen());
@ -359,23 +343,17 @@ QPDFAcroFormDocumentHelper::traverseField(
if (field.hasKey("/Parent")) { if (field.hasKey("/Parent")) {
is_field = true; is_field = true;
} }
if (field.hasKey("/Subtype") || field.hasKey("/Rect") || if (field.hasKey("/Subtype") || field.hasKey("/Rect") || field.hasKey("/AP")) {
field.hasKey("/AP")) {
is_annotation = true; is_annotation = true;
} }
} }
QTC::TC( QTC::TC("qpdf", "QPDFAcroFormDocumentHelper field found", (depth == 0) ? 0 : 1);
"qpdf", "QPDFAcroFormDocumentHelper field found", (depth == 0) ? 0 : 1); QTC::TC("qpdf", "QPDFAcroFormDocumentHelper annotation found", (is_field ? 0 : 1));
QTC::TC(
"qpdf",
"QPDFAcroFormDocumentHelper annotation found",
(is_field ? 0 : 1));
if (is_annotation) { if (is_annotation) {
QPDFObjectHandle our_field = (is_field ? field : parent); QPDFObjectHandle our_field = (is_field ? field : parent);
m->field_to_annotations[our_field.getObjGen()].push_back( m->field_to_annotations[our_field.getObjGen()].push_back(QPDFAnnotationObjectHelper(field));
QPDFAnnotationObjectHelper(field));
m->annotation_to_field[og] = QPDFFormFieldObjectHelper(our_field); m->annotation_to_field[og] = QPDFFormFieldObjectHelper(our_field);
} }
@ -400,8 +378,7 @@ QPDFAcroFormDocumentHelper::getNeedAppearances()
{ {
bool result = false; bool result = false;
QPDFObjectHandle acroform = this->qpdf.getRoot().getKey("/AcroForm"); QPDFObjectHandle acroform = this->qpdf.getRoot().getKey("/AcroForm");
if (acroform.isDictionary() && if (acroform.isDictionary() && acroform.getKey("/NeedAppearances").isBool()) {
acroform.getKey("/NeedAppearances").isBool()) {
result = acroform.getKey("/NeedAppearances").getBoolValue(); result = acroform.getKey("/NeedAppearances").getBoolValue();
} }
return result; return result;
@ -418,8 +395,7 @@ QPDFAcroFormDocumentHelper::setNeedAppearances(bool val)
return; return;
} }
if (val) { if (val) {
acroform.replaceKey( acroform.replaceKey("/NeedAppearances", QPDFObjectHandle::newBool(true));
"/NeedAppearances", QPDFObjectHandle::newBool(true));
} else { } else {
acroform.removeKey("/NeedAppearances"); acroform.removeKey("/NeedAppearances");
} }
@ -472,8 +448,7 @@ QPDFAcroFormDocumentHelper::adjustInheritedFields(
// we may be put a value on the field that is unused. This is // we may be put a value on the field that is unused. This is
// harmless, so it's not worth trying to work around. // harmless, so it's not worth trying to work around.
auto has_explicit = [](QPDFFormFieldObjectHelper& field, auto has_explicit = [](QPDFFormFieldObjectHelper& field, std::string const& key) {
std::string const& key) {
if (field.getObjectHandle().hasKey(key)) { if (field.getObjectHandle().hasKey(key)) {
return true; return true;
} }
@ -490,16 +465,14 @@ QPDFAcroFormDocumentHelper::adjustInheritedFields(
std::string da = cur_field.getDefaultAppearance(); std::string da = cur_field.getDefaultAppearance();
if (da != from_default_da) { if (da != from_default_da) {
QTC::TC("qpdf", "QPDFAcroFormDocumentHelper override da"); QTC::TC("qpdf", "QPDFAcroFormDocumentHelper override da");
obj.replaceKey( obj.replaceKey("/DA", QPDFObjectHandle::newUnicodeString(from_default_da));
"/DA", QPDFObjectHandle::newUnicodeString(from_default_da));
} }
} }
if (override_q && (!has_explicit(cur_field, "/Q"))) { if (override_q && (!has_explicit(cur_field, "/Q"))) {
int q = cur_field.getQuadding(); int q = cur_field.getQuadding();
if (q != from_default_q) { if (q != from_default_q) {
QTC::TC("qpdf", "QPDFAcroFormDocumentHelper override q"); QTC::TC("qpdf", "QPDFAcroFormDocumentHelper override q");
obj.replaceKey( obj.replaceKey("/Q", QPDFObjectHandle::newInteger(from_default_q));
"/Q", QPDFObjectHandle::newInteger(from_default_q));
} }
} }
} }
@ -511,11 +484,8 @@ namespace
{ {
public: public:
ResourceReplacer( ResourceReplacer(
std::map<std::string, std::map<std::string, std::string>> const& std::map<std::string, std::map<std::string, std::string>> const& dr_map,
dr_map, std::map<std::string, std::map<std::string, std::set<size_t>>> const& rnames);
std::map<
std::string,
std::map<std::string, std::set<size_t>>> const& rnames);
virtual ~ResourceReplacer() = default; virtual ~ResourceReplacer() = default;
virtual void handleToken(QPDFTokenizer::Token const&) override; virtual void handleToken(QPDFTokenizer::Token const&) override;
@ -527,8 +497,7 @@ namespace
ResourceReplacer::ResourceReplacer( ResourceReplacer::ResourceReplacer(
std::map<std::string, std::map<std::string, std::string>> const& dr_map, std::map<std::string, std::map<std::string, std::string>> const& dr_map,
std::map<std::string, std::map<std::string, std::set<size_t>>> const& std::map<std::string, std::map<std::string, std::set<size_t>>> const& rnames) :
rnames) :
offset(0) offset(0)
{ {
// We have: // We have:
@ -564,8 +533,7 @@ ResourceReplacer::handleToken(QPDFTokenizer::Token const& token)
{ {
bool wrote = false; bool wrote = false;
if (token.getType() == QPDFTokenizer::tt_name) { if (token.getType() == QPDFTokenizer::tt_name) {
std::string name = std::string name = QPDFObjectHandle::newName(token.getValue()).getName();
QPDFObjectHandle::newName(token.getValue()).getName();
if (to_replace.count(name) && to_replace[name].count(offset)) { if (to_replace.count(name) && to_replace[name].count(offset)) {
QTC::TC("qpdf", "QPDFAcroFormDocumentHelper replaced DA token"); QTC::TC("qpdf", "QPDFAcroFormDocumentHelper replaced DA token");
write(to_replace[name][offset]); write(to_replace[name][offset]);
@ -580,8 +548,7 @@ ResourceReplacer::handleToken(QPDFTokenizer::Token const& token)
void void
QPDFAcroFormDocumentHelper::adjustDefaultAppearances( QPDFAcroFormDocumentHelper::adjustDefaultAppearances(
QPDFObjectHandle obj, QPDFObjectHandle obj, std::map<std::string, std::map<std::string, std::string>> const& dr_map)
std::map<std::string, std::map<std::string, std::string>> const& dr_map)
{ {
// This method is called on a field that has been copied from // This method is called on a field that has been copied from
// another file but whose /DA still refers to resources in the // another file but whose /DA still refers to resources in the
@ -624,8 +591,7 @@ QPDFAcroFormDocumentHelper::adjustDefaultAppearances(
// then filter it. We don't attach the stream to anything, so it // then filter it. We don't attach the stream to anything, so it
// will get discarded. // will get discarded.
ResourceFinder rf; ResourceFinder rf;
auto da_stream = auto da_stream = QPDFObjectHandle::newStream(&this->qpdf, DA.getUTF8Value());
QPDFObjectHandle::newStream(&this->qpdf, DA.getUTF8Value());
try { try {
auto nwarnings = this->qpdf.numWarnings(); auto nwarnings = this->qpdf.numWarnings();
da_stream.parseAsContents(&rf); da_stream.parseAsContents(&rf);
@ -646,15 +612,13 @@ QPDFAcroFormDocumentHelper::adjustDefaultAppearances(
Pl_Buffer buf_pl("filtered DA"); Pl_Buffer buf_pl("filtered DA");
da_stream.filterAsContents(&rr, &buf_pl); da_stream.filterAsContents(&rr, &buf_pl);
auto buf = buf_pl.getBufferSharedPointer(); auto buf = buf_pl.getBufferSharedPointer();
std::string new_da( std::string new_da(reinterpret_cast<char*>(buf->getBuffer()), buf->getSize());
reinterpret_cast<char*>(buf->getBuffer()), buf->getSize());
obj.replaceKey("/DA", QPDFObjectHandle::newString(new_da)); obj.replaceKey("/DA", QPDFObjectHandle::newString(new_da));
} }
void void
QPDFAcroFormDocumentHelper::adjustAppearanceStream( QPDFAcroFormDocumentHelper::adjustAppearanceStream(
QPDFObjectHandle stream, QPDFObjectHandle stream, std::map<std::string, std::map<std::string, std::string>> dr_map)
std::map<std::string, std::map<std::string, std::string>> dr_map)
{ {
// We don't have to modify appearance streams or their resource // We don't have to modify appearance streams or their resource
// dictionaries for them to display properly, but we need to do so // dictionaries for them to display properly, but we need to do so
@ -740,8 +704,7 @@ QPDFAcroFormDocumentHelper::adjustAppearanceStream(
} catch (std::exception& e) { } catch (std::exception& e) {
// No way to reproduce in test suite right now since error // No way to reproduce in test suite right now since error
// conditions are converted to warnings. // conditions are converted to warnings.
stream.warnIfPossible( stream.warnIfPossible(std::string("Unable to parse appearance stream: ") + e.what());
std::string("Unable to parse appearance stream: ") + e.what());
} }
} }
@ -839,8 +802,7 @@ QPDFAcroFormDocumentHelper::transformAnnotations(
} }
dr.makeResourcesIndirect(this->qpdf); dr.makeResourcesIndirect(this->qpdf);
if (!dr.isIndirect()) { if (!dr.isIndirect()) {
dr = acroform.replaceKeyAndGetNew( dr = acroform.replaceKeyAndGetNew("/DR", this->qpdf.makeIndirectObject(dr));
"/DR", this->qpdf.makeIndirectObject(dr));
} }
// Merge the other document's /DR, creating a conflict // Merge the other document's /DR, creating a conflict
// map. mergeResources checks to make sure both objects // map. mergeResources checks to make sure both objects
@ -969,8 +931,7 @@ QPDFAcroFormDocumentHelper::transformAnnotations(
obj.replaceKey("/Parent", orig_to_copy[parent_og]); obj.replaceKey("/Parent", orig_to_copy[parent_og]);
} else { } else {
parent.warnIfPossible( parent.warnIfPossible(
"while traversing field " + "while traversing field " + obj.getObjGen().unparse(',') +
obj.getObjGen().unparse(',') +
", found parent (" + parent_og.unparse(',') + ", found parent (" + parent_og.unparse(',') +
") that had not been seen, indicating likely" ") that had not been seen, indicating likely"
" invalid field structure"); " invalid field structure");
@ -989,11 +950,7 @@ QPDFAcroFormDocumentHelper::transformAnnotations(
if (override_da || override_q) { if (override_da || override_q) {
adjustInheritedFields( adjustInheritedFields(
obj, obj, override_da, from_default_da, override_q, from_default_q);
override_da,
from_default_da,
override_q,
from_default_q);
} }
if (foreign) { if (foreign) {
// Lazily initialize our /DR and the conflict map. // Lazily initialize our /DR and the conflict map.
@ -1013,8 +970,7 @@ QPDFAcroFormDocumentHelper::transformAnnotations(
obj.replaceKey("/DR", dr); obj.replaceKey("/DR", dr);
} }
} }
if (foreign && obj.getKey("/DA").isString() && if (foreign && obj.getKey("/DA").isString() && (!dr_map.empty())) {
(!dr_map.empty())) {
adjustDefaultAppearances(obj, dr_map); adjustDefaultAppearances(obj, dr_map);
} }
} }
@ -1060,15 +1016,13 @@ QPDFAcroFormDocumentHelper::transformAnnotations(
if (apdict.isDictionary()) { if (apdict.isDictionary()) {
for (auto& ap: apdict.ditems()) { for (auto& ap: apdict.ditems()) {
if (ap.second.isStream()) { if (ap.second.isStream()) {
streams.push_back( streams.push_back(replace_stream(apdict, ap.first, ap.second));
replace_stream(apdict, ap.first, ap.second));
} else if (ap.second.isDictionary()) { } else if (ap.second.isDictionary()) {
for (auto& ap2: ap.second.ditems()) { for (auto& ap2: ap.second.ditems()) {
if (ap2.second.isStream()) { if (ap2.second.isStream()) {
streams.push_back( streams.push_back(
// line-break // line-break
replace_stream( replace_stream(ap.second, ap2.first, ap2.second));
ap.second, ap2.first, ap2.second));
} }
} }
} }
@ -1096,8 +1050,7 @@ QPDFAcroFormDocumentHelper::transformAnnotations(
adjustAppearanceStream(stream, dr_map); adjustAppearanceStream(stream, dr_map);
} }
} }
auto rect = auto rect = cm.transformRectangle(annot.getKey("/Rect").getArrayAsRectangle());
cm.transformRectangle(annot.getKey("/Rect").getArrayAsRectangle());
annot.replaceKey("/Rect", QPDFObjectHandle::newFromRectangle(rect)); annot.replaceKey("/Rect", QPDFObjectHandle::newFromRectangle(rect));
} }
} }

View File

@ -47,8 +47,7 @@ QPDFAnnotationObjectHelper::getFlags()
} }
QPDFObjectHandle QPDFObjectHandle
QPDFAnnotationObjectHelper::getAppearanceStream( QPDFAnnotationObjectHelper::getAppearanceStream(std::string const& which, std::string const& state)
std::string const& which, std::string const& state)
{ {
QPDFObjectHandle ap = getAppearanceDictionary(); QPDFObjectHandle ap = getAppearanceDictionary();
std::string desired_state = state.empty() ? getAppearanceState() : state; std::string desired_state = state.empty() ? getAppearanceState() : state;
@ -80,10 +79,7 @@ QPDFAnnotationObjectHelper::getAppearanceStream(
std::string std::string
QPDFAnnotationObjectHelper::getPageContentForAppearance( QPDFAnnotationObjectHelper::getPageContentForAppearance(
std::string const& name, std::string const& name, int rotate, int required_flags, int forbidden_flags)
int rotate,
int required_flags,
int forbidden_flags)
{ {
if (!getAppearanceStream("/N").isStream()) { if (!getAppearanceStream("/N").isStream()) {
return ""; return "";
@ -242,9 +238,7 @@ QPDFAnnotationObjectHelper::getPageContentForAppearance(
// Compute a matrix to transform the appearance box to the rectangle // Compute a matrix to transform the appearance box to the rectangle
QPDFMatrix AA; QPDFMatrix AA;
AA.translate(rect.llx, rect.lly); AA.translate(rect.llx, rect.lly);
AA.scale( AA.scale((rect.urx - rect.llx) / (T.urx - T.llx), (rect.ury - rect.lly) / (T.ury - T.lly));
(rect.urx - rect.llx) / (T.urx - T.llx),
(rect.ury - rect.lly) / (T.ury - T.lly));
AA.translate(-T.llx, -T.lly); AA.translate(-T.llx, -T.lly);
if (do_rotate) { if (do_rotate) {
AA.rotatex90(rotate); AA.rotatex90(rotate);

View File

@ -9,8 +9,7 @@
#include <cstring> #include <cstring>
#include <iostream> #include <iostream>
QPDFArgParser::Members::Members( QPDFArgParser::Members::Members(int argc, char const* const argv[], char const* progname_env) :
int argc, char const* const argv[], char const* progname_env) :
argc(argc), argc(argc),
argv(argv), argv(argv),
@ -25,19 +24,15 @@ QPDFArgParser::Members::Members(
whoami = QUtil::getWhoami(tmp.get()); whoami = QUtil::getWhoami(tmp.get());
} }
QPDFArgParser::QPDFArgParser( QPDFArgParser::QPDFArgParser(int argc, char const* const argv[], char const* progname_env) :
int argc, char const* const argv[], char const* progname_env) :
m(new Members(argc, argv, progname_env)) m(new Members(argc, argv, progname_env))
{ {
selectHelpOptionTable(); selectHelpOptionTable();
char const* help_choices[] = {"all", nullptr}; char const* help_choices[] = {"all", nullptr};
// More help choices are added dynamically. // More help choices are added dynamically.
addChoices( addChoices("help", bindParam(&QPDFArgParser::argHelp, this), false, help_choices);
"help", bindParam(&QPDFArgParser::argHelp, this), false, help_choices); addInvalidChoiceHandler("help", bindParam(&QPDFArgParser::invalidHelpArg, this));
addInvalidChoiceHandler( addBare("completion-bash", bindBare(&QPDFArgParser::argCompletionBash, this));
"help", bindParam(&QPDFArgParser::invalidHelpArg, this));
addBare(
"completion-bash", bindBare(&QPDFArgParser::argCompletionBash, this));
addBare("completion-zsh", bindBare(&QPDFArgParser::argCompletionZsh, this)); addBare("completion-zsh", bindBare(&QPDFArgParser::argCompletionZsh, this));
selectMainOptionTable(); selectMainOptionTable();
} }
@ -62,22 +57,19 @@ QPDFArgParser::selectOptionTable(std::string const& name)
auto t = m->option_tables.find(name); auto t = m->option_tables.find(name);
if (t == m->option_tables.end()) { if (t == m->option_tables.end()) {
QTC::TC("libtests", "QPDFArgParser select unregistered table"); QTC::TC("libtests", "QPDFArgParser select unregistered table");
throw std::logic_error( throw std::logic_error("QPDFArgParser: selecting unregistered option table " + name);
"QPDFArgParser: selecting unregistered option table " + name);
} }
m->option_table = &(t->second); m->option_table = &(t->second);
m->option_table_name = name; m->option_table_name = name;
} }
void void
QPDFArgParser::registerOptionTable( QPDFArgParser::registerOptionTable(std::string const& name, bare_arg_handler_t end_handler)
std::string const& name, bare_arg_handler_t end_handler)
{ {
if (0 != m->option_tables.count(name)) { if (0 != m->option_tables.count(name)) {
QTC::TC("libtests", "QPDFArgParser register registered table"); QTC::TC("libtests", "QPDFArgParser register registered table");
throw std::logic_error( throw std::logic_error(
"QPDFArgParser: registering already registered option table " + "QPDFArgParser: registering already registered option table " + name);
name);
} }
m->option_tables[name]; m->option_tables[name];
selectOptionTable(name); selectOptionTable(name);
@ -90,8 +82,8 @@ QPDFArgParser::registerArg(std::string const& arg)
if (0 != m->option_table->count(arg)) { if (0 != m->option_table->count(arg)) {
QTC::TC("libtests", "QPDFArgParser duplicate handler"); QTC::TC("libtests", "QPDFArgParser duplicate handler");
throw std::logic_error( throw std::logic_error(
"QPDFArgParser: adding a duplicate handler for option " + arg + "QPDFArgParser: adding a duplicate handler for option " + arg + " in " +
" in " + m->option_table_name + " option table"); m->option_table_name + " option table");
} }
return ((*m->option_table)[arg]); return ((*m->option_table)[arg]);
} }
@ -113,9 +105,7 @@ QPDFArgParser::addBare(std::string const& arg, bare_arg_handler_t handler)
void void
QPDFArgParser::addRequiredParameter( QPDFArgParser::addRequiredParameter(
std::string const& arg, std::string const& arg, param_arg_handler_t handler, char const* parameter_name)
param_arg_handler_t handler,
char const* parameter_name)
{ {
OptionEntry& oe = registerArg(arg); OptionEntry& oe = registerArg(arg);
oe.parameter_needed = true; oe.parameter_needed = true;
@ -124,8 +114,7 @@ QPDFArgParser::addRequiredParameter(
} }
void void
QPDFArgParser::addOptionalParameter( QPDFArgParser::addOptionalParameter(std::string const& arg, param_arg_handler_t handler)
std::string const& arg, param_arg_handler_t handler)
{ {
OptionEntry& oe = registerArg(arg); OptionEntry& oe = registerArg(arg);
oe.parameter_needed = false; oe.parameter_needed = false;
@ -134,10 +123,7 @@ QPDFArgParser::addOptionalParameter(
void void
QPDFArgParser::addChoices( QPDFArgParser::addChoices(
std::string const& arg, std::string const& arg, param_arg_handler_t handler, bool required, char const** choices)
param_arg_handler_t handler,
bool required,
char const** choices)
{ {
OptionEntry& oe = registerArg(arg); OptionEntry& oe = registerArg(arg);
oe.parameter_needed = required; oe.parameter_needed = required;
@ -148,15 +134,13 @@ QPDFArgParser::addChoices(
} }
void void
QPDFArgParser::addInvalidChoiceHandler( QPDFArgParser::addInvalidChoiceHandler(std::string const& arg, param_arg_handler_t handler)
std::string const& arg, param_arg_handler_t handler)
{ {
auto i = m->option_table->find(arg); auto i = m->option_table->find(arg);
if (i == m->option_table->end()) { if (i == m->option_table->end()) {
QTC::TC("libtests", "QPDFArgParser invalid choice handler to unknown"); QTC::TC("libtests", "QPDFArgParser invalid choice handler to unknown");
throw std::logic_error( throw std::logic_error("QPDFArgParser: attempt to add invalid choice handler"
"QPDFArgParser: attempt to add invalid choice handler" " to unknown argument");
" to unknown argument");
} }
auto& oe = i->second; auto& oe = i->second;
oe.invalid_choice_handler = handler; oe.invalid_choice_handler = handler;
@ -195,9 +179,7 @@ QPDFArgParser::completionCommon(bool zsh)
std::string appimage; std::string appimage;
if (QUtil::get_env(m->progname_env.c_str(), &executable)) { if (QUtil::get_env(m->progname_env.c_str(), &executable)) {
progname = executable; progname = executable;
} else if ( } else if (QUtil::get_env("APPDIR", &appdir) && QUtil::get_env("APPIMAGE", &appimage)) {
QUtil::get_env("APPDIR", &appdir) &&
QUtil::get_env("APPIMAGE", &appimage)) {
// Detect if we're in an AppImage and adjust // Detect if we're in an AppImage and adjust
if ((appdir.length() < strlen(m->argv[0])) && if ((appdir.length() < strlen(m->argv[0])) &&
(strncmp(appdir.c_str(), m->argv[0], appdir.length()) == 0)) { (strncmp(appdir.c_str(), m->argv[0], appdir.length()) == 0)) {
@ -345,8 +327,7 @@ QPDFArgParser::handleBashArguments()
} }
// Explicitly discard any non-space-terminated word. The "current // Explicitly discard any non-space-terminated word. The "current
// word" is handled specially. // word" is handled specially.
m->bash_argv_ph = m->bash_argv_ph = QUtil::make_shared_array<char const*>(1 + m->bash_argv.size());
QUtil::make_shared_array<char const*>(1 + m->bash_argv.size());
for (size_t i = 0; i < m->bash_argv.size(); ++i) { for (size_t i = 0; i < m->bash_argv.size(); ++i) {
m->bash_argv_ph.get()[i] = m->bash_argv.at(i).get(); m->bash_argv_ph.get()[i] = m->bash_argv.at(i).get();
} }
@ -479,8 +460,7 @@ QPDFArgParser::parseArgs()
end_option = true; end_option = true;
if (oep == m->option_table->end()) { if (oep == m->option_table->end()) {
// This is registered automatically, so this can't happen. // This is registered automatically, so this can't happen.
throw std::logic_error( throw std::logic_error("QPDFArgParser: -- handler not registered");
"QPDFArgParser: -- handler not registered");
} }
} else if ((arg[0] == '-') && (strcmp(arg, "-") != 0)) { } else if ((arg[0] == '-') && (strcmp(arg, "-") != 0)) {
++arg; ++arg;
@ -531,18 +511,15 @@ QPDFArgParser::parseArgs()
QTC::TC("libtests", "QPDFArgParser unrecognized"); QTC::TC("libtests", "QPDFArgParser unrecognized");
std::string message = "unrecognized argument " + o_arg; std::string message = "unrecognized argument " + o_arg;
if (m->option_table != &m->main_option_table) { if (m->option_table != &m->main_option_table) {
message += " (" + m->option_table_name + message += " (" + m->option_table_name + " options must be terminated with --)";
" options must be terminated with --)";
} }
usage(message); usage(message);
} }
OptionEntry& oe = oep->second; OptionEntry& oe = oep->second;
if ((oe.parameter_needed && (!have_parameter)) || if ((oe.parameter_needed && (!have_parameter)) ||
((!oe.choices.empty() && have_parameter && ((!oe.choices.empty() && have_parameter && (0 == oe.choices.count(parameter))))) {
(0 == oe.choices.count(parameter))))) { std::string message = "--" + arg_s + " must be given as --" + arg_s + "=";
std::string message =
"--" + arg_s + " must be given as --" + arg_s + "=";
if (oe.invalid_choice_handler) { if (oe.invalid_choice_handler) {
oe.invalid_choice_handler(parameter); oe.invalid_choice_handler(parameter);
// Method should call usage() or exit. Just in case it // Method should call usage() or exit. Just in case it
@ -609,9 +586,7 @@ QPDFArgParser::doFinalChecks()
void void
QPDFArgParser::addChoicesToCompletions( QPDFArgParser::addChoicesToCompletions(
option_table_t& option_table, option_table_t& option_table, std::string const& option, std::string const& extra_prefix)
std::string const& option,
std::string const& extra_prefix)
{ {
if (option_table.count(option) != 0) { if (option_table.count(option) != 0) {
OptionEntry& oe = option_table[option]; OptionEntry& oe = option_table[option];
@ -648,9 +623,7 @@ QPDFArgParser::addOptionsToCompletions(option_table_t& option_table)
void void
QPDFArgParser::insertCompletions( QPDFArgParser::insertCompletions(
option_table_t& option_table, option_table_t& option_table, std::string const& choice_option, std::string const& extra_prefix)
std::string const& choice_option,
std::string const& extra_prefix)
{ {
if (!choice_option.empty()) { if (!choice_option.empty()) {
addChoicesToCompletions(option_table, choice_option, extra_prefix); addChoicesToCompletions(option_table, choice_option, extra_prefix);
@ -666,21 +639,17 @@ QPDFArgParser::handleCompletion()
if (m->completions.empty()) { if (m->completions.empty()) {
// Detect --option=... Bash treats the = as a word separator. // Detect --option=... Bash treats the = as a word separator.
std::string choice_option; std::string choice_option;
if (m->bash_cur.empty() && (m->bash_prev.length() > 2) && if (m->bash_cur.empty() && (m->bash_prev.length() > 2) && (m->bash_prev.at(0) == '-') &&
(m->bash_prev.at(0) == '-') && (m->bash_prev.at(1) == '-') && (m->bash_prev.at(1) == '-') && (m->bash_line.at(m->bash_line.length() - 1) == '=')) {
(m->bash_line.at(m->bash_line.length() - 1) == '=')) {
choice_option = m->bash_prev.substr(2, std::string::npos); choice_option = m->bash_prev.substr(2, std::string::npos);
} else if ( } else if ((m->bash_prev == "=") && (m->bash_line.length() > (m->bash_cur.length() + 1))) {
(m->bash_prev == "=") &&
(m->bash_line.length() > (m->bash_cur.length() + 1))) {
// We're sitting at --option=x. Find previous option. // We're sitting at --option=x. Find previous option.
size_t end_mark = m->bash_line.length() - m->bash_cur.length() - 1; size_t end_mark = m->bash_line.length() - m->bash_cur.length() - 1;
char before_cur = m->bash_line.at(end_mark); char before_cur = m->bash_line.at(end_mark);
if (before_cur == '=') { if (before_cur == '=') {
size_t space = m->bash_line.find_last_of(' ', end_mark); size_t space = m->bash_line.find_last_of(' ', end_mark);
if (space != std::string::npos) { if (space != std::string::npos) {
std::string candidate = std::string candidate = m->bash_line.substr(space + 1, end_mark - space - 1);
m->bash_line.substr(space + 1, end_mark - space - 1);
if ((candidate.length() > 2) && (candidate.at(0) == '-') && if ((candidate.length() > 2) && (candidate.at(0) == '-') &&
(candidate.at(1) == '-')) { (candidate.at(1) == '-')) {
choice_option = candidate.substr(2, std::string::npos); choice_option = candidate.substr(2, std::string::npos);
@ -695,8 +664,7 @@ QPDFArgParser::handleCompletion()
insertCompletions(*m->option_table, choice_option, extra_prefix); insertCompletions(*m->option_table, choice_option, extra_prefix);
if (m->argc == 1) { if (m->argc == 1) {
// Help options are valid only by themselves. // Help options are valid only by themselves.
insertCompletions( insertCompletions(m->help_option_table, choice_option, extra_prefix);
m->help_option_table, choice_option, extra_prefix);
} }
} }
std::string prefix = extra_prefix + m->bash_cur; std::string prefix = extra_prefix + m->bash_cur;
@ -716,24 +684,19 @@ QPDFArgParser::addHelpFooter(std::string const& text)
void void
QPDFArgParser::addHelpTopic( QPDFArgParser::addHelpTopic(
std::string const& topic, std::string const& topic, std::string const& short_text, std::string const& long_text)
std::string const& short_text,
std::string const& long_text)
{ {
if (topic == "all") { if (topic == "all") {
QTC::TC("libtests", "QPDFArgParser add reserved help topic"); QTC::TC("libtests", "QPDFArgParser add reserved help topic");
throw std::logic_error( throw std::logic_error("QPDFArgParser: can't register reserved help topic " + topic);
"QPDFArgParser: can't register reserved help topic " + topic);
} }
if (!((topic.length() > 0) && (topic.at(0) != '-'))) { if (!((topic.length() > 0) && (topic.at(0) != '-'))) {
QTC::TC("libtests", "QPDFArgParser bad topic for help"); QTC::TC("libtests", "QPDFArgParser bad topic for help");
throw std::logic_error( throw std::logic_error("QPDFArgParser: help topics must not start with -");
"QPDFArgParser: help topics must not start with -");
} }
if (m->help_topics.count(topic)) { if (m->help_topics.count(topic)) {
QTC::TC("libtests", "QPDFArgParser add existing topic"); QTC::TC("libtests", "QPDFArgParser add existing topic");
throw std::logic_error( throw std::logic_error("QPDFArgParser: topic " + topic + " has already been added");
"QPDFArgParser: topic " + topic + " has already been added");
} }
m->help_topics[topic] = HelpTopic(short_text, long_text); m->help_topics[topic] = HelpTopic(short_text, long_text);
@ -747,23 +710,20 @@ QPDFArgParser::addOptionHelp(
std::string const& short_text, std::string const& short_text,
std::string const& long_text) std::string const& long_text)
{ {
if (!((option_name.length() > 2) && (option_name.at(0) == '-') && if (!((option_name.length() > 2) && (option_name.at(0) == '-') && (option_name.at(1) == '-'))) {
(option_name.at(1) == '-'))) {
QTC::TC("libtests", "QPDFArgParser bad option for help"); QTC::TC("libtests", "QPDFArgParser bad option for help");
throw std::logic_error( throw std::logic_error("QPDFArgParser: options for help must start with --");
"QPDFArgParser: options for help must start with --");
} }
if (m->option_help.count(option_name)) { if (m->option_help.count(option_name)) {
QTC::TC("libtests", "QPDFArgParser duplicate option help"); QTC::TC("libtests", "QPDFArgParser duplicate option help");
throw std::logic_error( throw std::logic_error("QPDFArgParser: option " + option_name + " already has help");
"QPDFArgParser: option " + option_name + " already has help");
} }
auto ht = m->help_topics.find(topic); auto ht = m->help_topics.find(topic);
if (ht == m->help_topics.end()) { if (ht == m->help_topics.end()) {
QTC::TC("libtests", "QPDFArgParser add to unknown topic"); QTC::TC("libtests", "QPDFArgParser add to unknown topic");
throw std::logic_error( throw std::logic_error(
"QPDFArgParser: unable to add option " + option_name + "QPDFArgParser: unable to add option " + option_name + " to unknown help topic " +
" to unknown help topic " + topic); topic);
} }
m->option_help[option_name] = HelpTopic(short_text, long_text); m->option_help[option_name] = HelpTopic(short_text, long_text);
ht->second.options.insert(option_name); ht->second.options.insert(option_name);
@ -773,12 +733,9 @@ QPDFArgParser::addOptionHelp(
void void
QPDFArgParser::getTopHelp(std::ostringstream& msg) QPDFArgParser::getTopHelp(std::ostringstream& msg)
{ {
msg << "Run \"" << m->whoami << " --help=topic\" for help on a topic." msg << "Run \"" << m->whoami << " --help=topic\" for help on a topic." << std::endl
<< std::endl << "Run \"" << m->whoami << " --help=--option\" for help on an option." << std::endl
<< "Run \"" << m->whoami << " --help=--option\" for help on an option." << "Run \"" << m->whoami << " --help=all\" to see all available help." << std::endl
<< std::endl
<< "Run \"" << m->whoami << " --help=all\" to see all available help."
<< std::endl
<< std::endl << std::endl
<< "Topics:" << std::endl; << "Topics:" << std::endl;
for (auto const& i: m->help_topics) { for (auto const& i: m->help_topics) {
@ -794,8 +751,7 @@ QPDFArgParser::getAllHelp(std::ostringstream& msg)
for (auto const& i: topics) { for (auto const& i: topics) {
auto const& topic = i.first; auto const& topic = i.first;
msg << std::endl msg << std::endl
<< "== " << topic << " (" << i.second.short_text << "== " << topic << " (" << i.second.short_text << ") ==" << std::endl
<< ") ==" << std::endl
<< std::endl; << std::endl;
getTopicHelp(topic, i.second, msg); getTopicHelp(topic, i.second, msg);
} }
@ -806,8 +762,7 @@ QPDFArgParser::getAllHelp(std::ostringstream& msg)
} }
void void
QPDFArgParser::getTopicHelp( QPDFArgParser::getTopicHelp(std::string const& name, HelpTopic const& ht, std::ostringstream& msg)
std::string const& name, HelpTopic const& ht, std::ostringstream& msg)
{ {
if (ht.long_text.empty()) { if (ht.long_text.empty()) {
msg << ht.short_text << std::endl; msg << ht.short_text << std::endl;
@ -817,8 +772,7 @@ QPDFArgParser::getTopicHelp(
if (!ht.options.empty()) { if (!ht.options.empty()) {
msg << std::endl << "Related options:" << std::endl; msg << std::endl << "Related options:" << std::endl;
for (auto const& i: ht.options) { for (auto const& i: ht.options) {
msg << " " << i << ": " << m->option_help[i].short_text msg << " " << i << ": " << m->option_help[i].short_text << std::endl;
<< std::endl;
} }
} }
} }

View File

@ -19,8 +19,7 @@ QPDFCryptoProvider::getImpl()
{ {
QPDFCryptoProvider& p = getInstance(); QPDFCryptoProvider& p = getInstance();
if (p.m->default_provider.empty()) { if (p.m->default_provider.empty()) {
throw std::logic_error( throw std::logic_error("QPDFCryptoProvider::getImpl called with no default provider.");
"QPDFCryptoProvider::getImpl called with no default provider.");
} }
return p.getImpl_internal(p.m->default_provider); return p.getImpl_internal(p.m->default_provider);
} }
@ -76,8 +75,7 @@ QPDFCryptoProvider::getImpl_internal(std::string const& name) const
auto iter = m->providers.find(name); auto iter = m->providers.find(name);
if (iter == m->providers.end()) { if (iter == m->providers.end()) {
throw std::logic_error( throw std::logic_error(
"QPDFCryptoProvider requested unknown implementation \"" + name + "QPDFCryptoProvider requested unknown implementation \"" + name + "\"");
"\"");
} }
return m->providers[name](); return m->providers[name]();
} }

View File

@ -47,8 +47,7 @@ QPDFCrypto_gnutls::MD5_init()
if (code < 0) { if (code < 0) {
this->hash_ctx = nullptr; this->hash_ctx = nullptr;
throw std::runtime_error( throw std::runtime_error(
std::string("gnutls: MD5 error: ") + std::string("gnutls: MD5 error: ") + std::string(gnutls_strerror(code)));
std::string(gnutls_strerror(code)));
} }
} }
@ -78,26 +77,22 @@ QPDFCrypto_gnutls::RC4_init(unsigned char const* key_data, int key_len)
{ {
RC4_finalize(); RC4_finalize();
if (key_len == -1) { if (key_len == -1) {
key_len = key_len = QIntC::to_int(strlen(reinterpret_cast<char const*>(key_data)));
QIntC::to_int(strlen(reinterpret_cast<char const*>(key_data)));
} }
gnutls_datum_t key; gnutls_datum_t key;
key.data = const_cast<unsigned char*>(key_data); key.data = const_cast<unsigned char*>(key_data);
key.size = QIntC::to_uint(key_len); key.size = QIntC::to_uint(key_len);
int code = gnutls_cipher_init( int code = gnutls_cipher_init(&this->cipher_ctx, GNUTLS_CIPHER_ARCFOUR_128, &key, nullptr);
&this->cipher_ctx, GNUTLS_CIPHER_ARCFOUR_128, &key, nullptr);
if (code < 0) { if (code < 0) {
this->cipher_ctx = nullptr; this->cipher_ctx = nullptr;
throw std::runtime_error( throw std::runtime_error(
std::string("gnutls: RC4 error: ") + std::string("gnutls: RC4 error: ") + std::string(gnutls_strerror(code)));
std::string(gnutls_strerror(code)));
} }
} }
void void
QPDFCrypto_gnutls::RC4_process( QPDFCrypto_gnutls::RC4_process(unsigned char const* in_data, size_t len, unsigned char* out_data)
unsigned char const* in_data, size_t len, unsigned char* out_data)
{ {
gnutls_cipher_encrypt2(this->cipher_ctx, in_data, len, out_data, len); gnutls_cipher_encrypt2(this->cipher_ctx, in_data, len, out_data, len);
} }
@ -223,29 +218,19 @@ QPDFCrypto_gnutls::rijndael_init(
if (code < 0) { if (code < 0) {
this->cipher_ctx = nullptr; this->cipher_ctx = nullptr;
throw std::runtime_error( throw std::runtime_error(
std::string("gnutls: AES error: ") + std::string("gnutls: AES error: ") + std::string(gnutls_strerror(code)));
std::string(gnutls_strerror(code)));
} }
} }
void void
QPDFCrypto_gnutls::rijndael_process( QPDFCrypto_gnutls::rijndael_process(unsigned char* in_data, unsigned char* out_data)
unsigned char* in_data, unsigned char* out_data)
{ {
if (this->encrypt) { if (this->encrypt) {
gnutls_cipher_encrypt2( gnutls_cipher_encrypt2(
this->cipher_ctx, this->cipher_ctx, in_data, rijndael_buf_size, out_data, rijndael_buf_size);
in_data,
rijndael_buf_size,
out_data,
rijndael_buf_size);
} else { } else {
gnutls_cipher_decrypt2( gnutls_cipher_decrypt2(
this->cipher_ctx, this->cipher_ctx, in_data, rijndael_buf_size, out_data, rijndael_buf_size);
in_data,
rijndael_buf_size,
out_data,
rijndael_buf_size);
} }
// Gnutls doesn't support AES in ECB (non-CBC) mode, but the // Gnutls doesn't support AES in ECB (non-CBC) mode, but the
@ -253,14 +238,8 @@ QPDFCrypto_gnutls::rijndael_process(
// zeroes each time. We jump through a few hoops here to make this // zeroes each time. We jump through a few hoops here to make this
// work. // work.
if (!this->cbc_mode) { if (!this->cbc_mode) {
static unsigned char zeroes[16] = { static unsigned char zeroes[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; rijndael_init(this->encrypt, this->aes_key_data, this->aes_key_len, false, zeroes);
rijndael_init(
this->encrypt,
this->aes_key_data,
this->aes_key_len,
false,
zeroes);
} }
} }

View File

@ -68,8 +68,7 @@ QPDFCrypto_native::RC4_init(unsigned char const* key_data, int key_len)
} }
void void
QPDFCrypto_native::RC4_process( QPDFCrypto_native::RC4_process(unsigned char const* in_data, size_t len, unsigned char* out_data)
unsigned char const* in_data, size_t len, unsigned char* out_data)
{ {
this->rc4->process(in_data, len, out_data); this->rc4->process(in_data, len, out_data);
} }
@ -112,13 +111,12 @@ QPDFCrypto_native::rijndael_init(
unsigned char* cbc_block) unsigned char* cbc_block)
{ {
this->aes_pdf = std::make_shared<AES_PDF_native>( this->aes_pdf =
encrypt, key_data, key_len, cbc_mode, cbc_block); std::make_shared<AES_PDF_native>(encrypt, key_data, key_len, cbc_mode, cbc_block);
} }
void void
QPDFCrypto_native::rijndael_process( QPDFCrypto_native::rijndael_process(unsigned char* in_data, unsigned char* out_data)
unsigned char* in_data, unsigned char* out_data)
{ {
this->aes_pdf->update(in_data, out_data); this->aes_pdf->update(in_data, out_data);
} }

View File

@ -76,8 +76,7 @@ RC4Loader::~RC4Loader()
static void static void
bad_bits(int bits) bad_bits(int bits)
{ {
throw std::logic_error( throw std::logic_error(std::string("unsupported key length: ") + std::to_string(bits));
std::string("unsupported key length: ") + std::to_string(bits));
} }
static void static void
@ -208,14 +207,11 @@ QPDFCrypto_openssl::RC4_init(unsigned char const* key_data, int key_len)
#endif #endif
check_openssl(EVP_CIPHER_CTX_reset(cipher_ctx)); check_openssl(EVP_CIPHER_CTX_reset(cipher_ctx));
if (key_len == -1) { if (key_len == -1) {
key_len = key_len = QIntC::to_int(strlen(reinterpret_cast<const char*>(key_data)));
QIntC::to_int(strlen(reinterpret_cast<const char*>(key_data)));
} }
check_openssl( check_openssl(EVP_EncryptInit_ex(cipher_ctx, rc4, nullptr, nullptr, nullptr));
EVP_EncryptInit_ex(cipher_ctx, rc4, nullptr, nullptr, nullptr));
check_openssl(EVP_CIPHER_CTX_set_key_length(cipher_ctx, key_len)); check_openssl(EVP_CIPHER_CTX_set_key_length(cipher_ctx, key_len));
check_openssl( check_openssl(EVP_EncryptInit_ex(cipher_ctx, nullptr, nullptr, key_data, nullptr));
EVP_EncryptInit_ex(cipher_ctx, nullptr, nullptr, key_data, nullptr));
} }
void void
@ -242,23 +238,19 @@ QPDFCrypto_openssl::rijndael_init(
check_openssl(EVP_CIPHER_CTX_reset(cipher_ctx)); check_openssl(EVP_CIPHER_CTX_reset(cipher_ctx));
check_openssl( check_openssl(
// line-break // line-break
EVP_CipherInit_ex( EVP_CipherInit_ex(cipher_ctx, cipher, nullptr, key_data, cbc_block, encrypt));
cipher_ctx, cipher, nullptr, key_data, cbc_block, encrypt));
check_openssl(EVP_CIPHER_CTX_set_padding(cipher_ctx, 0)); check_openssl(EVP_CIPHER_CTX_set_padding(cipher_ctx, 0));
} }
void void
QPDFCrypto_openssl::RC4_process( QPDFCrypto_openssl::RC4_process(unsigned char const* in_data, size_t len, unsigned char* out_data)
unsigned char const* in_data, size_t len, unsigned char* out_data)
{ {
int out_len = static_cast<int>(len); int out_len = static_cast<int>(len);
check_openssl( check_openssl(EVP_EncryptUpdate(cipher_ctx, out_data, &out_len, in_data, out_len));
EVP_EncryptUpdate(cipher_ctx, out_data, &out_len, in_data, out_len));
} }
void void
QPDFCrypto_openssl::rijndael_process( QPDFCrypto_openssl::rijndael_process(unsigned char* in_data, unsigned char* out_data)
unsigned char* in_data, unsigned char* out_data)
{ {
int len = QPDFCryptoImpl::rijndael_buf_size; int len = QPDFCryptoImpl::rijndael_buf_size;
check_openssl(EVP_CipherUpdate(cipher_ctx, out_data, &len, in_data, len)); check_openssl(EVP_CipherUpdate(cipher_ctx, out_data, &len, in_data, len));

View File

@ -24,13 +24,12 @@ QPDFEFStreamObjectHelper::getParam(std::string const& pkey)
} }
void void
QPDFEFStreamObjectHelper::setParam( QPDFEFStreamObjectHelper::setParam(std::string const& pkey, QPDFObjectHandle const& pval)
std::string const& pkey, QPDFObjectHandle const& pval)
{ {
auto params = this->oh.getDict().getKey("/Params"); auto params = this->oh.getDict().getKey("/Params");
if (!params.isDictionary()) { if (!params.isDictionary()) {
params = this->oh.getDict().replaceKeyAndGetNew( params =
"/Params", QPDFObjectHandle::newDictionary()); this->oh.getDict().replaceKeyAndGetNew("/Params", QPDFObjectHandle::newDictionary());
} }
params.replaceKey(pkey, pval); params.replaceKey(pkey, pval);
} }
@ -89,8 +88,7 @@ QPDFEFStreamObjectHelper::getChecksum()
} }
QPDFEFStreamObjectHelper QPDFEFStreamObjectHelper
QPDFEFStreamObjectHelper::createEFStream( QPDFEFStreamObjectHelper::createEFStream(QPDF& qpdf, std::shared_ptr<Buffer> data)
QPDF& qpdf, std::shared_ptr<Buffer> data)
{ {
return newFromStream(qpdf.newStream(data)); return newFromStream(qpdf.newStream(data));
} }
@ -102,12 +100,10 @@ QPDFEFStreamObjectHelper::createEFStream(QPDF& qpdf, std::string const& data)
} }
QPDFEFStreamObjectHelper QPDFEFStreamObjectHelper
QPDFEFStreamObjectHelper::createEFStream( QPDFEFStreamObjectHelper::createEFStream(QPDF& qpdf, std::function<void(Pipeline*)> provider)
QPDF& qpdf, std::function<void(Pipeline*)> provider)
{ {
auto stream = qpdf.newStream(); auto stream = qpdf.newStream();
stream.replaceStreamData( stream.replaceStreamData(provider, QPDFObjectHandle::newNull(), QPDFObjectHandle::newNull());
provider, QPDFObjectHandle::newNull(), QPDFObjectHandle::newNull());
return newFromStream(stream); return newFromStream(stream);
} }
@ -128,8 +124,7 @@ QPDFEFStreamObjectHelper::setModDate(std::string const& date)
QPDFEFStreamObjectHelper& QPDFEFStreamObjectHelper&
QPDFEFStreamObjectHelper::setSubtype(std::string const& subtype) QPDFEFStreamObjectHelper::setSubtype(std::string const& subtype)
{ {
this->oh.getDict().replaceKey( this->oh.getDict().replaceKey("/Subtype", QPDFObjectHandle::newName("/" + subtype));
"/Subtype", QPDFObjectHandle::newName("/" + subtype));
return *this; return *this;
} }
@ -137,22 +132,18 @@ QPDFEFStreamObjectHelper
QPDFEFStreamObjectHelper::newFromStream(QPDFObjectHandle stream) QPDFEFStreamObjectHelper::newFromStream(QPDFObjectHandle stream)
{ {
QPDFEFStreamObjectHelper result(stream); QPDFEFStreamObjectHelper result(stream);
stream.getDict().replaceKey( stream.getDict().replaceKey("/Type", QPDFObjectHandle::newName("/EmbeddedFile"));
"/Type", QPDFObjectHandle::newName("/EmbeddedFile"));
Pl_Discard discard; Pl_Discard discard;
// The PDF spec specifies use of MD5 here and notes that it is not // The PDF spec specifies use of MD5 here and notes that it is not
// to be used for security. MD5 is known to be insecure. // to be used for security. MD5 is known to be insecure.
Pl_MD5 md5("EF md5", &discard); Pl_MD5 md5("EF md5", &discard);
Pl_Count count("EF size", &md5); Pl_Count count("EF size", &md5);
if (!stream.pipeStreamData(&count, nullptr, 0, qpdf_dl_all)) { if (!stream.pipeStreamData(&count, nullptr, 0, qpdf_dl_all)) {
stream.warnIfPossible( stream.warnIfPossible("unable to get stream data for new embedded file stream");
"unable to get stream data for new embedded file stream");
} else { } else {
result.setParam("/Size", QPDFObjectHandle::newInteger(count.getCount()));
result.setParam( result.setParam(
"/Size", QPDFObjectHandle::newInteger(count.getCount())); "/CheckSum", QPDFObjectHandle::newString(QUtil::hex_decode(md5.getHexDigest())));
result.setParam(
"/CheckSum",
QPDFObjectHandle::newString(QUtil::hex_decode(md5.getHexDigest())));
} }
return result; return result;
} }

View File

@ -40,8 +40,7 @@ QPDFEmbeddedFileDocumentHelper::QPDFEmbeddedFileDocumentHelper(QPDF& qpdf) :
if (names.isDictionary()) { if (names.isDictionary()) {
auto embedded_files = names.getKey("/EmbeddedFiles"); auto embedded_files = names.getKey("/EmbeddedFiles");
if (embedded_files.isDictionary()) { if (embedded_files.isDictionary()) {
m->embedded_files = std::make_shared<QPDFNameTreeObjectHelper>( m->embedded_files = std::make_shared<QPDFNameTreeObjectHelper>(embedded_files, qpdf);
embedded_files, qpdf);
} }
} }
} }
@ -61,8 +60,7 @@ QPDFEmbeddedFileDocumentHelper::initEmbeddedFiles()
auto root = qpdf.getRoot(); auto root = qpdf.getRoot();
auto names = root.getKey("/Names"); auto names = root.getKey("/Names");
if (!names.isDictionary()) { if (!names.isDictionary()) {
names = root.replaceKeyAndGetNew( names = root.replaceKeyAndGetNew("/Names", QPDFObjectHandle::newDictionary());
"/Names", QPDFObjectHandle::newDictionary());
} }
auto embedded_files = names.getKey("/EmbeddedFiles"); auto embedded_files = names.getKey("/EmbeddedFiles");
if (!embedded_files.isDictionary()) { if (!embedded_files.isDictionary()) {
@ -91,8 +89,7 @@ QPDFEmbeddedFileDocumentHelper::getEmbeddedFiles()
std::map<std::string, std::shared_ptr<QPDFFileSpecObjectHelper>> result; std::map<std::string, std::shared_ptr<QPDFFileSpecObjectHelper>> result;
if (m->embedded_files) { if (m->embedded_files) {
for (auto const& i: *(m->embedded_files)) { for (auto const& i: *(m->embedded_files)) {
result[i.first] = result[i.first] = std::make_shared<QPDFFileSpecObjectHelper>(i.second);
std::make_shared<QPDFFileSpecObjectHelper>(i.second);
} }
} }
return result; return result;

View File

@ -19,8 +19,7 @@ QPDFFileSpecObjectHelper::QPDFFileSpecObjectHelper(QPDFObjectHandle oh) :
} }
} }
static std::vector<std::string> name_keys = { static std::vector<std::string> name_keys = {"/UF", "/F", "/Unix", "/DOS", "/Mac"};
"/UF", "/F", "/Unix", "/DOS", "/Mac"};
std::string std::string
QPDFFileSpecObjectHelper::getDescription() QPDFFileSpecObjectHelper::getDescription()
@ -90,8 +89,7 @@ QPDFFileSpecObjectHelper::createFileSpec(
return createFileSpec( return createFileSpec(
qpdf, qpdf,
filename, filename,
QPDFEFStreamObjectHelper::createEFStream( QPDFEFStreamObjectHelper::createEFStream(qpdf, QUtil::file_provider(fullpath)));
qpdf, QUtil::file_provider(fullpath)));
} }
QPDFFileSpecObjectHelper QPDFFileSpecObjectHelper

View File

@ -76,9 +76,7 @@ QPDFFormFieldObjectHelper::getInheritableFieldValue(std::string const& name)
node = node.getKey("/Parent"); node = node.getKey("/Parent");
result = node.getKey(name); result = node.getKey(name);
if (!result.isNull()) { if (!result.isNull()) {
QTC::TC( QTC::TC("qpdf", "QPDFFormFieldObjectHelper non-trivial inheritance");
"qpdf",
"QPDFFormFieldObjectHelper non-trivial inheritance");
return result; return result;
} }
} }
@ -87,8 +85,7 @@ QPDFFormFieldObjectHelper::getInheritableFieldValue(std::string const& name)
} }
std::string std::string
QPDFFormFieldObjectHelper::getInheritableFieldValueAsString( QPDFFormFieldObjectHelper::getInheritableFieldValueAsString(std::string const& name)
std::string const& name)
{ {
QPDFObjectHandle fv = getInheritableFieldValue(name); QPDFObjectHandle fv = getInheritableFieldValue(name);
std::string result; std::string result;
@ -99,8 +96,7 @@ QPDFFormFieldObjectHelper::getInheritableFieldValueAsString(
} }
std::string std::string
QPDFFormFieldObjectHelper::getInheritableFieldValueAsName( QPDFFormFieldObjectHelper::getInheritableFieldValueAsName(std::string const& name)
std::string const& name)
{ {
QPDFObjectHandle fv = getInheritableFieldValue(name); QPDFObjectHandle fv = getInheritableFieldValue(name);
std::string result; std::string result;
@ -125,9 +121,7 @@ QPDFFormFieldObjectHelper::getFullyQualifiedName()
while (!node.isNull() && seen.add(node)) { while (!node.isNull() && seen.add(node)) {
if (node.getKey("/T").isString()) { if (node.getKey("/T").isString()) {
if (!result.empty()) { if (!result.empty()) {
QTC::TC( QTC::TC("qpdf", "QPDFFormFieldObjectHelper non-trivial qualified name");
"qpdf",
"QPDFFormFieldObjectHelper non-trivial qualified name");
result = "." + result; result = "." + result;
} }
result = node.getKey("/T").getUTF8Value() + result; result = node.getKey("/T").getUTF8Value() + result;
@ -210,10 +204,7 @@ QPDFFormFieldObjectHelper::getDefaultAppearance()
} }
std::string result; std::string result;
if (value.isString()) { if (value.isString()) {
QTC::TC( QTC::TC("qpdf", "QPDFFormFieldObjectHelper DA present", looked_in_acroform ? 0 : 1);
"qpdf",
"QPDFFormFieldObjectHelper DA present",
looked_in_acroform ? 0 : 1);
result = value.getUTF8Value(); result = value.getUTF8Value();
} }
return result; return result;
@ -230,10 +221,7 @@ QPDFFormFieldObjectHelper::getQuadding()
} }
int result = 0; int result = 0;
if (fv.isInteger()) { if (fv.isInteger()) {
QTC::TC( QTC::TC("qpdf", "QPDFFormFieldObjectHelper Q present", looked_in_acroform ? 0 : 1);
"qpdf",
"QPDFFormFieldObjectHelper Q present",
looked_in_acroform ? 0 : 1);
result = QIntC::to_int(fv.getIntValue()); result = QIntC::to_int(fv.getIntValue());
} }
return result; return result;
@ -255,25 +243,19 @@ QPDFFormFieldObjectHelper::isText()
bool bool
QPDFFormFieldObjectHelper::isCheckbox() QPDFFormFieldObjectHelper::isCheckbox()
{ {
return ( return ((getFieldType() == "/Btn") && ((getFlags() & (ff_btn_radio | ff_btn_pushbutton)) == 0));
(getFieldType() == "/Btn") &&
((getFlags() & (ff_btn_radio | ff_btn_pushbutton)) == 0));
} }
bool bool
QPDFFormFieldObjectHelper::isRadioButton() QPDFFormFieldObjectHelper::isRadioButton()
{ {
return ( return ((getFieldType() == "/Btn") && ((getFlags() & ff_btn_radio) == ff_btn_radio));
(getFieldType() == "/Btn") &&
((getFlags() & ff_btn_radio) == ff_btn_radio));
} }
bool bool
QPDFFormFieldObjectHelper::isPushbutton() QPDFFormFieldObjectHelper::isPushbutton()
{ {
return ( return ((getFieldType() == "/Btn") && ((getFlags() & ff_btn_pushbutton) == ff_btn_pushbutton));
(getFieldType() == "/Btn") &&
((getFlags() & ff_btn_pushbutton) == ff_btn_pushbutton));
} }
bool bool
@ -303,15 +285,13 @@ QPDFFormFieldObjectHelper::getChoices()
} }
void void
QPDFFormFieldObjectHelper::setFieldAttribute( QPDFFormFieldObjectHelper::setFieldAttribute(std::string const& key, QPDFObjectHandle value)
std::string const& key, QPDFObjectHandle value)
{ {
this->oh.replaceKey(key, value); this->oh.replaceKey(key, value);
} }
void void
QPDFFormFieldObjectHelper::setFieldAttribute( QPDFFormFieldObjectHelper::setFieldAttribute(std::string const& key, std::string const& utf8_value)
std::string const& key, std::string const& utf8_value)
{ {
this->oh.replaceKey(key, QPDFObjectHandle::newUnicodeString(utf8_value)); this->oh.replaceKey(key, QPDFObjectHandle::newUnicodeString(utf8_value));
} }
@ -330,41 +310,36 @@ QPDFFormFieldObjectHelper::setV(QPDFObjectHandle value, bool need_appearances)
} }
} }
if (!okay) { if (!okay) {
this->oh.warnIfPossible( this->oh.warnIfPossible("ignoring attempt to set a checkbox field to a"
"ignoring attempt to set a checkbox field to a" " value of other than /Yes or /Off");
" value of other than /Yes or /Off");
} }
} else if (isRadioButton()) { } else if (isRadioButton()) {
if (value.isName()) { if (value.isName()) {
setRadioButtonValue(value); setRadioButtonValue(value);
} else { } else {
this->oh.warnIfPossible( this->oh.warnIfPossible("ignoring attempt to set a radio button field to"
"ignoring attempt to set a radio button field to" " an object that is not a name");
" an object that is not a name");
} }
} else if (isPushbutton()) { } else if (isPushbutton()) {
this->oh.warnIfPossible( this->oh.warnIfPossible("ignoring attempt set the value of a pushbutton field");
"ignoring attempt set the value of a pushbutton field");
} }
return; return;
} }
if (value.isString()) { if (value.isString()) {
setFieldAttribute( setFieldAttribute("/V", QPDFObjectHandle::newUnicodeString(value.getUTF8Value()));
"/V", QPDFObjectHandle::newUnicodeString(value.getUTF8Value()));
} else { } else {
setFieldAttribute("/V", value); setFieldAttribute("/V", value);
} }
if (need_appearances) { if (need_appearances) {
QPDF& qpdf = this->oh.getQPDF( QPDF& qpdf =
"QPDFFormFieldObjectHelper::setV called with need_appearances = " this->oh.getQPDF("QPDFFormFieldObjectHelper::setV called with need_appearances = "
"true on an object that is not associated with an owning QPDF"); "true on an object that is not associated with an owning QPDF");
QPDFAcroFormDocumentHelper(qpdf).setNeedAppearances(true); QPDFAcroFormDocumentHelper(qpdf).setNeedAppearances(true);
} }
} }
void void
QPDFFormFieldObjectHelper::setV( QPDFFormFieldObjectHelper::setV(std::string const& utf8_value, bool need_appearances)
std::string const& utf8_value, bool need_appearances)
{ {
setV(QPDFObjectHandle::newUnicodeString(utf8_value), need_appearances); setV(QPDFObjectHandle::newUnicodeString(utf8_value), need_appearances);
} }
@ -390,8 +365,7 @@ QPDFFormFieldObjectHelper::setRadioButtonValue(QPDFObjectHandle name)
if (ph.isRadioButton()) { if (ph.isRadioButton()) {
// This is most likely one of the individual buttons. Try // This is most likely one of the individual buttons. Try
// calling on the parent. // calling on the parent.
QTC::TC( QTC::TC("qpdf", "QPDFFormFieldObjectHelper set parent radio button");
"qpdf", "QPDFFormFieldObjectHelper set parent radio button");
ph.setRadioButtonValue(name); ph.setRadioButtonValue(name);
return; return;
} }
@ -419,9 +393,7 @@ QPDFFormFieldObjectHelper::setRadioButtonValue(QPDFObjectHandle name)
QPDFObjectHandle grandkid = grandkids.getArrayItem(j); QPDFObjectHandle grandkid = grandkids.getArrayItem(j);
AP = grandkid.getKey("/AP"); AP = grandkid.getKey("/AP");
if (!AP.isNull()) { if (!AP.isNull()) {
QTC::TC( QTC::TC("qpdf", "QPDFFormFieldObjectHelper radio button grandkid");
"qpdf",
"QPDFFormFieldObjectHelper radio button grandkid");
annot = grandkid; annot = grandkid;
break; break;
} }
@ -432,8 +404,7 @@ QPDFFormFieldObjectHelper::setRadioButtonValue(QPDFObjectHandle name)
} }
if (!annot.isInitialized()) { if (!annot.isInitialized()) {
QTC::TC("qpdf", "QPDFObjectHandle broken radio button"); QTC::TC("qpdf", "QPDFObjectHandle broken radio button");
this->oh.warnIfPossible( this->oh.warnIfPossible("unable to set the value of this radio button");
"unable to set the value of this radio button");
continue; continue;
} }
if (AP.isDictionary() && AP.getKey("/N").isDictionary() && if (AP.isDictionary() && AP.getKey("/N").isDictionary() &&
@ -465,9 +436,7 @@ QPDFFormFieldObjectHelper::setCheckBoxValue(bool value)
QPDFObjectHandle kid = kids.getArrayItem(i); QPDFObjectHandle kid = kids.getArrayItem(i);
AP = kid.getKey("/AP"); AP = kid.getKey("/AP");
if (!AP.isNull()) { if (!AP.isNull()) {
QTC::TC( QTC::TC("qpdf", "QPDFFormFieldObjectHelper checkbox kid widget");
"qpdf",
"QPDFFormFieldObjectHelper checkbox kid widget");
annot = kid; annot = kid;
break; break;
} }
@ -555,8 +524,7 @@ ValueSetter::handleToken(QPDFTokenizer::Token const& token)
break; break;
case st_bmc: case st_bmc:
if ((ttype == QPDFTokenizer::tt_space) || if ((ttype == QPDFTokenizer::tt_space) || (ttype == QPDFTokenizer::tt_comment)) {
(ttype == QPDFTokenizer::tt_comment)) {
writeToken(token); writeToken(token);
} else { } else {
state = st_emc; state = st_emc;
@ -642,9 +610,7 @@ ValueSetter::writeAppearance()
} }
highlight = true; highlight = true;
highlight_idx = found_idx - QIntC::to_size(wanted_first); highlight_idx = found_idx - QIntC::to_size(wanted_first);
for (size_t i = QIntC::to_size(wanted_first); for (size_t i = QIntC::to_size(wanted_first); i <= QIntC::to_size(wanted_last); ++i) {
i <= QIntC::to_size(wanted_last);
++i) {
lines.push_back(opt.at(i)); lines.push_back(opt.at(i));
} }
} else { } else {
@ -661,14 +627,12 @@ ValueSetter::writeAppearance()
// Write the lines centered vertically, highlighting if needed // Write the lines centered vertically, highlighting if needed
size_t nlines = lines.size(); size_t nlines = lines.size();
double dy = bbox.ury - double dy = bbox.ury - ((bbox.ury - bbox.lly - (static_cast<double>(nlines) * tfh)) / 2.0);
((bbox.ury - bbox.lly - (static_cast<double>(nlines) * tfh)) / 2.0);
if (highlight) { if (highlight) {
write( write(
"q\n0.85 0.85 0.85 rg\n" + QUtil::double_to_string(bbox.llx) + " " + "q\n0.85 0.85 0.85 rg\n" + QUtil::double_to_string(bbox.llx) + " " +
QUtil::double_to_string( QUtil::double_to_string(
bbox.lly + dy - bbox.lly + dy - (tfh * (static_cast<double>(highlight_idx + 1)))) +
(tfh * (static_cast<double>(highlight_idx + 1)))) +
" " + QUtil::double_to_string(bbox.urx - bbox.llx) + " " + " " + QUtil::double_to_string(bbox.urx - bbox.llx) + " " +
QUtil::double_to_string(tfh) + " re f\nQ\n"); QUtil::double_to_string(tfh) + " re f\nQ\n");
} }
@ -681,10 +645,8 @@ ValueSetter::writeAppearance()
// which doesn't seem really worth the effort. // which doesn't seem really worth the effort.
if (i == 0) { if (i == 0) {
write( write(
QUtil::double_to_string(bbox.llx + static_cast<double>(dx)) + QUtil::double_to_string(bbox.llx + static_cast<double>(dx)) + " " +
" " + QUtil::double_to_string(bbox.lly + static_cast<double>(dy)) + " Td\n");
QUtil::double_to_string(bbox.lly + static_cast<double>(dy)) +
" Td\n");
} else { } else {
write("0 " + QUtil::double_to_string(-tfh) + " Td\n"); write("0 " + QUtil::double_to_string(-tfh) + " Td\n");
} }
@ -794,8 +756,7 @@ TfFinder::getFontName()
} }
QPDFObjectHandle QPDFObjectHandle
QPDFFormFieldObjectHelper::getFontFromResource( QPDFFormFieldObjectHelper::getFontFromResource(QPDFObjectHandle resources, std::string const& name)
QPDFObjectHandle resources, std::string const& name)
{ {
QPDFObjectHandle result; QPDFObjectHandle result;
if (resources.isDictionary() && resources.getKey("/Font").isDictionary() && if (resources.isDictionary() && resources.getKey("/Font").isDictionary() &&
@ -806,40 +767,34 @@ QPDFFormFieldObjectHelper::getFontFromResource(
} }
void void
QPDFFormFieldObjectHelper::generateTextAppearance( QPDFFormFieldObjectHelper::generateTextAppearance(QPDFAnnotationObjectHelper& aoh)
QPDFAnnotationObjectHelper& aoh)
{ {
QPDFObjectHandle AS = aoh.getAppearanceStream("/N"); QPDFObjectHandle AS = aoh.getAppearanceStream("/N");
if (AS.isNull()) { if (AS.isNull()) {
QTC::TC("qpdf", "QPDFFormFieldObjectHelper create AS from scratch"); QTC::TC("qpdf", "QPDFFormFieldObjectHelper create AS from scratch");
QPDFObjectHandle::Rectangle rect = aoh.getRect(); QPDFObjectHandle::Rectangle rect = aoh.getRect();
QPDFObjectHandle::Rectangle bbox( QPDFObjectHandle::Rectangle bbox(0, 0, rect.urx - rect.llx, rect.ury - rect.lly);
0, 0, rect.urx - rect.llx, rect.ury - rect.lly); QPDFObjectHandle dict =
QPDFObjectHandle dict = QPDFObjectHandle::parse( QPDFObjectHandle::parse("<< /Resources << /ProcSet [ /PDF /Text ] >>"
"<< /Resources << /ProcSet [ /PDF /Text ] >>" " /Type /XObject /Subtype /Form >>");
" /Type /XObject /Subtype /Form >>");
dict.replaceKey("/BBox", QPDFObjectHandle::newFromRectangle(bbox)); dict.replaceKey("/BBox", QPDFObjectHandle::newFromRectangle(bbox));
AS = QPDFObjectHandle::newStream( AS = QPDFObjectHandle::newStream(this->oh.getOwningQPDF(), "/Tx BMC\nEMC\n");
this->oh.getOwningQPDF(), "/Tx BMC\nEMC\n");
AS.replaceDict(dict); AS.replaceDict(dict);
QPDFObjectHandle AP = aoh.getAppearanceDictionary(); QPDFObjectHandle AP = aoh.getAppearanceDictionary();
if (AP.isNull()) { if (AP.isNull()) {
QTC::TC("qpdf", "QPDFFormFieldObjectHelper create AP from scratch"); QTC::TC("qpdf", "QPDFFormFieldObjectHelper create AP from scratch");
aoh.getObjectHandle().replaceKey( aoh.getObjectHandle().replaceKey("/AP", QPDFObjectHandle::newDictionary());
"/AP", QPDFObjectHandle::newDictionary());
AP = aoh.getAppearanceDictionary(); AP = aoh.getAppearanceDictionary();
} }
AP.replaceKey("/N", AS); AP.replaceKey("/N", AS);
} }
if (!AS.isStream()) { if (!AS.isStream()) {
aoh.getObjectHandle().warnIfPossible( aoh.getObjectHandle().warnIfPossible("unable to get normal appearance stream for update");
"unable to get normal appearance stream for update");
return; return;
} }
QPDFObjectHandle bbox_obj = AS.getDict().getKey("/BBox"); QPDFObjectHandle bbox_obj = AS.getDict().getKey("/BBox");
if (!bbox_obj.isRectangle()) { if (!bbox_obj.isRectangle()) {
aoh.getObjectHandle().warnIfPossible( aoh.getObjectHandle().warnIfPossible("unable to get appearance stream bounding box");
"unable to get appearance stream bounding box");
return; return;
} }
QPDFObjectHandle::Rectangle bbox = bbox_obj.getArrayAsRectangle(); QPDFObjectHandle::Rectangle bbox = bbox_obj.getArrayAsRectangle();
@ -872,8 +827,7 @@ QPDFFormFieldObjectHelper::generateTextAppearance(
if (found_font_in_dr && resources.isDictionary()) { if (found_font_in_dr && resources.isDictionary()) {
QTC::TC("qpdf", "QPDFFormFieldObjectHelper get font from /DR"); QTC::TC("qpdf", "QPDFFormFieldObjectHelper get font from /DR");
if (resources.isIndirect()) { if (resources.isIndirect()) {
resources = resources.getQPDF().makeIndirectObject( resources = resources.getQPDF().makeIndirectObject(resources.shallowCopy());
resources.shallowCopy());
AS.getDict().replaceKey("/Resources", resources); AS.getDict().replaceKey("/Resources", resources);
} }
// Use mergeResources to force /Font to be local // Use mergeResources to force /Font to be local
@ -899,6 +853,5 @@ QPDFFormFieldObjectHelper::generateTextAppearance(
AS.addTokenFilter( AS.addTokenFilter(
// line-break // line-break
std::shared_ptr<QPDFObjectHandle::TokenFilter>( std::shared_ptr<QPDFObjectHandle::TokenFilter>(new ValueSetter(DA, V, opt, tf, bbox)));
new ValueSetter(DA, V, opt, tf, bbox)));
} }

File diff suppressed because it is too large Load Diff

View File

@ -46,8 +46,7 @@ namespace
}; };
} // namespace } // namespace
ArgParser::ArgParser( ArgParser::ArgParser(QPDFArgParser& ap, std::shared_ptr<QPDFJob::Config> c_main) :
QPDFArgParser& ap, std::shared_ptr<QPDFJob::Config> c_main) :
ap(ap), ap(ap),
c_main(c_main), c_main(c_main),
pages_password(nullptr), pages_password(nullptr),
@ -107,8 +106,7 @@ ArgParser::argVersion()
auto whoami = this->ap.getProgname(); auto whoami = this->ap.getProgname();
*QPDFLogger::defaultLogger()->getInfo() *QPDFLogger::defaultLogger()->getInfo()
<< whoami << " version " << QPDF::QPDFVersion() << "\n" << whoami << " version " << QPDF::QPDFVersion() << "\n"
<< "Run " << whoami << "Run " << whoami << " --copyright to see copyright and license information.\n";
<< " --copyright to see copyright and license information.\n";
} }
void void
@ -152,8 +150,7 @@ ArgParser::argJsonHelp(std::string const& parameter)
if ((version < 1) || (version > JSON::LATEST)) { if ((version < 1) || (version > JSON::LATEST)) {
usage(std::string("unsupported json version ") + parameter); usage(std::string("unsupported json version ") + parameter);
} }
*QPDFLogger::defaultLogger()->getInfo() *QPDFLogger::defaultLogger()->getInfo() << QPDFJob::json_out_schema(version) << "\n";
<< QPDFJob::json_out_schema(version) << "\n";
} }
void void
@ -263,10 +260,7 @@ ArgParser::argPagesPositional(std::string const& arg)
if (range_p == nullptr) { if (range_p == nullptr) {
if (arg.empty()) { if (arg.empty()) {
// The filename or password was the last argument // The filename or password was the last argument
QTC::TC( QTC::TC("qpdf", "QPDFJob pages range omitted at end", this->pages_password ? 0 : 1);
"qpdf",
"QPDFJob pages range omitted at end",
this->pages_password ? 0 : 1);
} else { } else {
// We need to accumulate some more arguments // We need to accumulate some more arguments
return; return;

View File

@ -658,8 +658,7 @@ QPDFJob::Config::passwordFile(std::string const& parameter)
if (lines.size() > 1) { if (lines.size() > 1) {
*QPDFLogger::defaultLogger()->getError() *QPDFLogger::defaultLogger()->getError()
<< this->o.m->message_prefix << this->o.m->message_prefix << ": WARNING: all but the first line of"
<< ": WARNING: all but the first line of"
<< " the password file are ignored\n"; << " the password file are ignored\n";
} }
} }
@ -751,8 +750,7 @@ QPDFJob::Config::removeUnreferencedResources(std::string const& parameter)
QPDFJob::Config* QPDFJob::Config*
QPDFJob::Config::showObject(std::string const& parameter) QPDFJob::Config::showObject(std::string const& parameter)
{ {
QPDFJob::parse_object_id( QPDFJob::parse_object_id(parameter, o.m->show_trailer, o.m->show_obj, o.m->show_gen);
parameter, o.m->show_trailer, o.m->show_obj, o.m->show_gen);
o.m->require_outfile = false; o.m->require_outfile = false;
return this; return this;
} }
@ -761,13 +759,11 @@ QPDFJob::Config*
QPDFJob::Config::jobJsonFile(std::string const& parameter) QPDFJob::Config::jobJsonFile(std::string const& parameter)
{ {
try { try {
o.initializeFromJson( o.initializeFromJson(QUtil::read_file_into_string(parameter.c_str()), true);
QUtil::read_file_into_string(parameter.c_str()), true);
} catch (std::exception& e) { } catch (std::exception& e) {
throw std::runtime_error( throw std::runtime_error(
"error with job-json file " + std::string(parameter) + ": " + "error with job-json file " + std::string(parameter) + ": " + e.what() + "\nRun " +
e.what() + "\nRun " + this->o.m->message_prefix + this->o.m->message_prefix + " --job-json-help for information on the file format.");
" --job-json-help for information on the file format.");
} }
return this; return this;
} }
@ -900,8 +896,7 @@ QPDFJob::AttConfig::replace()
QPDFJob::Config* QPDFJob::Config*
QPDFJob::AttConfig::endAddAttachment() QPDFJob::AttConfig::endAddAttachment()
{ {
static std::string now = static std::string now = QUtil::qpdf_time_to_pdf_time(QUtil::get_current_qpdf_time());
QUtil::qpdf_time_to_pdf_time(QUtil::get_current_qpdf_time());
if (this->att.path.empty()) { if (this->att.path.empty()) {
usage("add attachment: no file specified"); usage("add attachment: no file specified");
} }
@ -953,8 +948,7 @@ QPDFJob::PagesConfig*
QPDFJob::PagesConfig::pageSpec( QPDFJob::PagesConfig::pageSpec(
std::string const& filename, std::string const& range, char const* password) std::string const& filename, std::string const& range, char const* password)
{ {
this->config->o.m->page_specs.push_back( this->config->o.m->page_specs.push_back(QPDFJob::PageSpec(filename, password, range));
QPDFJob::PageSpec(filename, password, range));
return this; return this;
} }
@ -1035,9 +1029,7 @@ QPDFJob::UOConfig::password(std::string const& parameter)
std::shared_ptr<QPDFJob::EncConfig> std::shared_ptr<QPDFJob::EncConfig>
QPDFJob::Config::encrypt( QPDFJob::Config::encrypt(
int keylen, int keylen, std::string const& user_password, std::string const& owner_password)
std::string const& user_password,
std::string const& owner_password)
{ {
o.m->keylen = keylen; o.m->keylen = keylen;
if (keylen == 256) { if (keylen == 256) {

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