2
1
mirror of https://github.com/qpdf/qpdf.git synced 2024-06-01 09:50:54 +00:00

Allow odd/even modifiers in numeric range (fixes #364)

This commit is contained in:
Jay Berkenbilt 2019-11-09 11:54:16 -05:00
parent c9cc83621b
commit c4478e5249
4 changed files with 81 additions and 5 deletions

View File

@ -1116,6 +1116,8 @@ QUtil::parse_numrange(char const* range, int max)
std::vector<int> work; std::vector<int> work;
static int const comma = -1; static int const comma = -1;
static int const dash = -2; static int const dash = -2;
size_t start_idx = 0;
size_t skip = 1;
enum { st_top, enum { st_top,
st_in_number, st_in_number,
@ -1182,6 +1184,14 @@ QUtil::parse_numrange(char const* range, int max)
work.push_back(dash); work.push_back(dash);
} }
} }
else if (ch == ':')
{
if (! ((state == st_in_number) || (state == st_after_number)))
{
throw std::runtime_error("unexpected colon");
}
break;
}
else else
{ {
throw std::runtime_error("unexpected character"); throw std::runtime_error("unexpected character");
@ -1197,6 +1207,22 @@ QUtil::parse_numrange(char const* range, int max)
{ {
throw std::runtime_error("number expected"); throw std::runtime_error("number expected");
} }
if (*p == ':')
{
if (strcmp(p, ":odd") == 0)
{
skip = 2;
}
else if (strcmp(p, ":even") == 0)
{
skip = 2;
start_idx = 1;
}
else
{
throw std::runtime_error("unexpected even/odd modifier");
}
}
p = 0; p = 0;
for (size_t i = 0; i < work.size(); i += 2) for (size_t i = 0; i < work.size(); i += 2)
@ -1245,6 +1271,15 @@ QUtil::parse_numrange(char const* range, int max)
} }
} }
} }
if ((start_idx > 0) || (skip != 1))
{
auto t = result;
result.clear();
for (size_t i = start_idx; i < t.size(); i += skip)
{
result.push_back(t.at(i));
}
}
} }
catch (std::runtime_error const& e) catch (std::runtime_error const& e)
{ {

View File

@ -49,6 +49,24 @@ my @nrange_tests = (
"numeric range r1-r15" . "numeric range r1-r15" .
" -> 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1", " -> 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1",
0], 0],
["1-10:quack",
"error at * in numeric range 1-10*:quack: unexpected even/odd modifier",
2],
["1-10:",
"error at * in numeric range 1-10*:: unexpected even/odd modifier",
2],
["1-10,r:",
"error at * in numeric range 1-10,r*:: unexpected even/odd modifier",
2],
["1-10,:",
"error at * in numeric range 1-10,*:: unexpected colon",
2],
["1-6,8-12:odd",
"numeric range 1-6,8-12:odd -> 1 3 5 8 10 12",
0],
["1-6,8-12:even",
"numeric range 1-6,8-12:even -> 2 4 6 9 11",
0],
); );
foreach my $d (@nrange_tests) foreach my $d (@nrange_tests)
{ {

View File

@ -1391,9 +1391,12 @@ make
<literal>r3-r1</literal> would be the last three pages of the <literal>r3-r1</literal> would be the last three pages of the
document. Pages can appear in any order. Ranges can appear with a document. Pages can appear in any order. Ranges can appear with a
high number followed by a low number, which causes the pages to high number followed by a low number, which causes the pages to
appear in reverse. Repeating a number will cause an error, but you appear in reverse. Numbers may be repeated in a page range. A page
can use the workaround discussed above should you really want to range may be optionally appended with <literal>:even</literal> or
include the same page twice. <literal>:odd</literal> to indicate only the even or odd pages in
the given range. Note that even and odd refer to the positions
within the specified, range, not whether the original number is
even or odd.
</para> </para>
<para> <para>
Example page ranges: Example page ranges:
@ -1420,6 +1423,18 @@ make
in reverse order in reverse order
</para> </para>
</listitem> </listitem>
<listitem>
<para>
<literal>1-20:even</literal>: even pages from 2 to 20
</para>
</listitem>
<listitem>
<para>
<literal>5,7-9,12:odd</literal>: pages 5, 8, and, 12, which are
the pages in odd positions from among the original range, which
represents pages 5, 7, 8, 9, and 12.
</para>
</listitem>
</itemizedlist> </itemizedlist>
</para> </para>
<para> <para>
@ -4663,6 +4678,13 @@ print "\n";
<xref linkend="ref.crypto"/>. <xref linkend="ref.crypto"/>.
</para> </para>
</listitem> </listitem>
<listitem>
<para>
Allow <literal>:even</literal> or <literal>:odd</literal> to
be appended to numeric ranges for specification of the even
or odd pages from among the pages specified in the range.
</para>
</listitem>
</itemizedlist> </itemizedlist>
</listitem> </listitem>
</itemizedlist> </itemizedlist>

View File

@ -1286,8 +1286,9 @@ ArgParser::argHelp()
<< "to count from the end, so \"r3-r1\" would be the last three pages of the\n" << "to count from the end, so \"r3-r1\" would be the last three pages of the\n"
<< "document. Pages can appear in any order. Ranges can appear with a\n" << "document. Pages can appear in any order. Ranges can appear with a\n"
<< "high number followed by a low number, which causes the pages to appear in\n" << "high number followed by a low number, which causes the pages to appear in\n"
<< "reverse. Repeating a number will cause an error, but the manual discusses\n" << "reverse. Numbers may be repeated. A page range may be appended with :odd\n"
<< "a workaround should you really want to include the same page twice.\n" << "to indicate odd pages in the selected range or :even to indicate even\n"
<< "pages.\n"
<< "\n" << "\n"
<< "If the page range is omitted, the range of 1-z is assumed. qpdf decides\n" << "If the page range is omitted, the range of 1-z is assumed. qpdf decides\n"
<< "that the page range is omitted if the range argument is either -- or a\n" << "that the page range is omitted if the range argument is either -- or a\n"