mirror of
https://github.com/qpdf/qpdf.git
synced 2024-11-01 03:12:29 +00:00
Better diagnostics when --pages is not closed (fixes #555)
This commit is contained in:
parent
f545f8b076
commit
7ed991343b
@ -1,3 +1,8 @@
|
|||||||
|
2021-11-02 Jay Berkenbilt <ejb@ql.org>
|
||||||
|
|
||||||
|
* Improve error reporting when someone forgets the -- after
|
||||||
|
--pages. Fixes #555.
|
||||||
|
|
||||||
2021-05-12 Jay Berkenbilt <ejb@ql.org>
|
2021-05-12 Jay Berkenbilt <ejb@ql.org>
|
||||||
|
|
||||||
* Bug fix: ensure we don't overflow any string bounds while
|
* Bug fix: ensure we don't overflow any string bounds while
|
||||||
|
54
qpdf/qpdf.cc
54
qpdf/qpdf.cc
@ -738,6 +738,21 @@ static void parse_object_id(std::string const& objspec,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool file_exists(char const* filename)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
fclose(QUtil::safe_fopen(filename, "rb"));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
catch (std::runtime_error&)
|
||||||
|
{
|
||||||
|
// can't open the file
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// This is not a general-purpose argument parser. It is tightly
|
// This is not a general-purpose argument parser. It is tightly
|
||||||
// crafted to work with qpdf. qpdf's command-line syntax is very
|
// crafted to work with qpdf. qpdf's command-line syntax is very
|
||||||
// complex because of its long history, and it doesn't really follow
|
// complex because of its long history, and it doesn't really follow
|
||||||
@ -2080,6 +2095,10 @@ void
|
|||||||
ArgParser::argPages()
|
ArgParser::argPages()
|
||||||
{
|
{
|
||||||
++cur_arg;
|
++cur_arg;
|
||||||
|
if (! o.page_specs.empty())
|
||||||
|
{
|
||||||
|
usage("the --pages may only be specified one time");
|
||||||
|
}
|
||||||
o.page_specs = parsePagesOptions();
|
o.page_specs = parsePagesOptions();
|
||||||
if (o.page_specs.empty())
|
if (o.page_specs.empty())
|
||||||
{
|
{
|
||||||
@ -2936,19 +2955,15 @@ ArgParser::handleArgFileArguments()
|
|||||||
{
|
{
|
||||||
char* argfile = 0;
|
char* argfile = 0;
|
||||||
if ((strlen(argv[i]) > 1) && (argv[i][0] == '@'))
|
if ((strlen(argv[i]) > 1) && (argv[i][0] == '@'))
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
{
|
||||||
argfile = 1 + argv[i];
|
argfile = 1 + argv[i];
|
||||||
if (strcmp(argfile, "-") != 0)
|
if (strcmp(argfile, "-") != 0)
|
||||||
{
|
{
|
||||||
fclose(QUtil::safe_fopen(argfile, "rb"));
|
if (! file_exists(argfile))
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (std::runtime_error&)
|
|
||||||
{
|
{
|
||||||
// The file's not there; treating as regular option
|
// The file's not there; treating as regular option
|
||||||
argfile = 0;
|
argfile = nullptr;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (argfile)
|
if (argfile)
|
||||||
@ -3220,6 +3235,16 @@ ArgParser::parseNumrange(char const* range, int max, bool throw_error)
|
|||||||
std::vector<PageSpec>
|
std::vector<PageSpec>
|
||||||
ArgParser::parsePagesOptions()
|
ArgParser::parsePagesOptions()
|
||||||
{
|
{
|
||||||
|
auto check_unclosed = [this](char const* arg, int n) {
|
||||||
|
if ((strlen(arg) > 0) && (arg[0] == '-'))
|
||||||
|
{
|
||||||
|
// A common error is to forget to close --pages with --,
|
||||||
|
// so catch this as special case
|
||||||
|
QTC::TC("qpdf", "check unclosed --pages", n);
|
||||||
|
usage("the --pages option must be terminated with -- by itself");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
std::vector<PageSpec> result;
|
std::vector<PageSpec> result;
|
||||||
while (1)
|
while (1)
|
||||||
{
|
{
|
||||||
@ -3234,6 +3259,10 @@ ArgParser::parsePagesOptions()
|
|||||||
char const* file = argv[cur_arg++];
|
char const* file = argv[cur_arg++];
|
||||||
char const* password = 0;
|
char const* password = 0;
|
||||||
char const* range = argv[cur_arg++];
|
char const* range = argv[cur_arg++];
|
||||||
|
if (! file_exists(file))
|
||||||
|
{
|
||||||
|
check_unclosed(file, 0);
|
||||||
|
}
|
||||||
if (strncmp(range, "--password=", 11) == 0)
|
if (strncmp(range, "--password=", 11) == 0)
|
||||||
{
|
{
|
||||||
// Oh, that's the password, not the range
|
// Oh, that's the password, not the range
|
||||||
@ -3263,23 +3292,20 @@ ArgParser::parsePagesOptions()
|
|||||||
catch (std::runtime_error& e1)
|
catch (std::runtime_error& e1)
|
||||||
{
|
{
|
||||||
// The range is invalid. Let's see if it's a file.
|
// The range is invalid. Let's see if it's a file.
|
||||||
try
|
range_omitted = true;
|
||||||
{
|
|
||||||
if (strcmp(range, ".") == 0)
|
if (strcmp(range, ".") == 0)
|
||||||
{
|
{
|
||||||
// "." means the input file.
|
// "." means the input file.
|
||||||
QTC::TC("qpdf", "qpdf pages range omitted with .");
|
QTC::TC("qpdf", "qpdf pages range omitted with .");
|
||||||
}
|
}
|
||||||
else
|
else if (file_exists(range))
|
||||||
{
|
{
|
||||||
fclose(QUtil::safe_fopen(range, "rb"));
|
|
||||||
QTC::TC("qpdf", "qpdf pages range omitted in middle");
|
QTC::TC("qpdf", "qpdf pages range omitted in middle");
|
||||||
// Yup, it's a file.
|
// Yup, it's a file.
|
||||||
}
|
}
|
||||||
range_omitted = true;
|
else
|
||||||
}
|
|
||||||
catch (std::runtime_error&)
|
|
||||||
{
|
{
|
||||||
|
check_unclosed(range, 1);
|
||||||
// Give the range error
|
// Give the range error
|
||||||
usage(e1.what());
|
usage(e1.what());
|
||||||
}
|
}
|
||||||
|
@ -594,3 +594,4 @@ qpdf copy fields non-first from orig 0
|
|||||||
QPDF resolve duplicated page in insert 0
|
QPDF resolve duplicated page in insert 0
|
||||||
QPDFWriter preserve object streams 1
|
QPDFWriter preserve object streams 1
|
||||||
QPDFWriter exclude from object stream 0
|
QPDFWriter exclude from object stream 0
|
||||||
|
check unclosed --pages 1
|
||||||
|
@ -139,7 +139,7 @@ foreach my $c (@completion_tests)
|
|||||||
show_ntests();
|
show_ntests();
|
||||||
# ----------
|
# ----------
|
||||||
$td->notify("--- Argument Parsing ---");
|
$td->notify("--- Argument Parsing ---");
|
||||||
$n_tests += 6;
|
$n_tests += 9;
|
||||||
|
|
||||||
$td->runtest("required argument",
|
$td->runtest("required argument",
|
||||||
{$td->COMMAND => "qpdf --password minimal.pdf"},
|
{$td->COMMAND => "qpdf --password minimal.pdf"},
|
||||||
@ -171,6 +171,21 @@ $td->runtest("extra overlay filename",
|
|||||||
{$td->REGEXP => ".*overlay file already specified.*",
|
{$td->REGEXP => ".*overlay file already specified.*",
|
||||||
$td->EXIT_STATUS => 2},
|
$td->EXIT_STATUS => 2},
|
||||||
$td->NORMALIZE_NEWLINES);
|
$td->NORMALIZE_NEWLINES);
|
||||||
|
$td->runtest("multiple pages options",
|
||||||
|
{$td->COMMAND => "qpdf --pages . -- --pages . --"},
|
||||||
|
{$td->REGEXP => ".*--pages may only be specified one time.*",
|
||||||
|
$td->EXIT_STATUS => 2},
|
||||||
|
$td->NORMALIZE_NEWLINES);
|
||||||
|
$td->runtest("bad numeric range detects unclosed --pages",
|
||||||
|
{$td->COMMAND => "qpdf --pages . --pages . --"},
|
||||||
|
{$td->REGEXP => ".*--pages option must be terminated with --.*",
|
||||||
|
$td->EXIT_STATUS => 2},
|
||||||
|
$td->NORMALIZE_NEWLINES);
|
||||||
|
$td->runtest("bad file detected as unclosed --pages",
|
||||||
|
{$td->COMMAND => "qpdf --pages . 1 --xyz out"},
|
||||||
|
{$td->REGEXP => ".*--pages option must be terminated with --.*",
|
||||||
|
$td->EXIT_STATUS => 2},
|
||||||
|
$td->NORMALIZE_NEWLINES);
|
||||||
|
|
||||||
show_ntests();
|
show_ntests();
|
||||||
# ----------
|
# ----------
|
||||||
|
Loading…
Reference in New Issue
Block a user