mirror of
https://github.com/qpdf/qpdf.git
synced 2025-01-05 08:02:11 +00:00
Add new integer accessors to QPDFObjectHandle
This commit is contained in:
parent
42306e2ff8
commit
3608afd5c5
@ -1,5 +1,9 @@
|
|||||||
2019-06-20 Jay Berkenbilt <ejb@ql.org>
|
2019-06-20 Jay Berkenbilt <ejb@ql.org>
|
||||||
|
|
||||||
|
* Add methods to QPDFObjectHandle to return the value of Integer
|
||||||
|
objects as int and unsigned int with range checking and fallback
|
||||||
|
behavior to avoid silent underflow/overflow conditions.
|
||||||
|
|
||||||
* Add functions to QUtil to convert unsigned integers to strings,
|
* Add functions to QUtil to convert unsigned integers to strings,
|
||||||
avoiding implicit conversion between unsigned and signed integer
|
avoiding implicit conversion between unsigned and signed integer
|
||||||
types.
|
types.
|
||||||
|
@ -491,6 +491,12 @@ class QPDFObjectHandle
|
|||||||
// Methods for integer objects
|
// Methods for integer objects
|
||||||
QPDF_DLL
|
QPDF_DLL
|
||||||
long long getIntValue();
|
long long getIntValue();
|
||||||
|
QPDF_DLL
|
||||||
|
int getIntValueAsInt();
|
||||||
|
QPDF_DLL
|
||||||
|
unsigned long long getUIntValue();
|
||||||
|
QPDF_DLL
|
||||||
|
unsigned int getUIntValueAsUInt();
|
||||||
|
|
||||||
// Methods for real objects
|
// Methods for real objects
|
||||||
QPDF_DLL
|
QPDF_DLL
|
||||||
|
@ -26,6 +26,7 @@
|
|||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
|
#include <limits.h>
|
||||||
|
|
||||||
class TerminateParsing
|
class TerminateParsing
|
||||||
{
|
{
|
||||||
@ -406,6 +407,82 @@ QPDFObjectHandle::getIntValue()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
QPDFObjectHandle::getIntValueAsInt()
|
||||||
|
{
|
||||||
|
int result = 0;
|
||||||
|
long long v = getIntValue();
|
||||||
|
if (v < INT_MIN)
|
||||||
|
{
|
||||||
|
QTC::TC("qpdf", "QPDFObjectHandle int returning INT_MIN");
|
||||||
|
warnIfPossible(
|
||||||
|
"requested value of integer is too small; returning INT_MIN",
|
||||||
|
false);
|
||||||
|
result = INT_MIN;
|
||||||
|
}
|
||||||
|
else if (v > INT_MAX)
|
||||||
|
{
|
||||||
|
QTC::TC("qpdf", "QPDFObjectHandle int returning INT_MAX");
|
||||||
|
warnIfPossible(
|
||||||
|
"requested value of integer is too big; returning INT_MAX",
|
||||||
|
false);
|
||||||
|
result = INT_MAX;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
result = static_cast<int>(v);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned long long
|
||||||
|
QPDFObjectHandle::getUIntValue()
|
||||||
|
{
|
||||||
|
unsigned long long result = 0;
|
||||||
|
long long v = getIntValue();
|
||||||
|
if (v < 0)
|
||||||
|
{
|
||||||
|
QTC::TC("qpdf", "QPDFObjectHandle uint returning 0");
|
||||||
|
warnIfPossible(
|
||||||
|
"unsigned value request for negative number; returning 0",
|
||||||
|
false);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
result = static_cast<unsigned long long>(v);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int
|
||||||
|
QPDFObjectHandle::getUIntValueAsUInt()
|
||||||
|
{
|
||||||
|
unsigned int result = 0;
|
||||||
|
long long v = getIntValue();
|
||||||
|
if (v < 0)
|
||||||
|
{
|
||||||
|
QTC::TC("qpdf", "QPDFObjectHandle uint uint returning 0");
|
||||||
|
warnIfPossible(
|
||||||
|
"unsigned integer value request for negative number; returning 0",
|
||||||
|
false);
|
||||||
|
result = 0;
|
||||||
|
}
|
||||||
|
else if (v > UINT_MAX)
|
||||||
|
{
|
||||||
|
QTC::TC("qpdf", "QPDFObjectHandle uint returning UINT_MAX");
|
||||||
|
warnIfPossible(
|
||||||
|
"requested value of unsigned integer is too big;"
|
||||||
|
" returning UINT_MAX",
|
||||||
|
false);
|
||||||
|
result = UINT_MAX;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
result = static_cast<unsigned int>(v);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
// Real accessors
|
// Real accessors
|
||||||
|
|
||||||
std::string
|
std::string
|
||||||
|
@ -440,3 +440,8 @@ QPDFPageObjectHelper keep inline image 0
|
|||||||
qpdf image optimize colorspace 0
|
qpdf image optimize colorspace 0
|
||||||
qpdf image optimize bits per component 0
|
qpdf image optimize bits per component 0
|
||||||
QPDFWriter remove empty DecodeParms 0
|
QPDFWriter remove empty DecodeParms 0
|
||||||
|
QPDFObjectHandle uint returning 0 0
|
||||||
|
QPDFObjectHandle int returning INT_MIN 0
|
||||||
|
QPDFObjectHandle int returning INT_MAX 0
|
||||||
|
QPDFObjectHandle uint returning UINT_MAX 0
|
||||||
|
QPDFObjectHandle uint uint returning 0 0
|
||||||
|
@ -2286,7 +2286,7 @@ my @badfiles = ("not a PDF file", # 1
|
|||||||
"bad dictionary key", # 36
|
"bad dictionary key", # 36
|
||||||
);
|
);
|
||||||
|
|
||||||
$n_tests += @badfiles + 5;
|
$n_tests += @badfiles + 6;
|
||||||
|
|
||||||
# Test 6 contains errors in the free table consistency, but we no
|
# Test 6 contains errors in the free table consistency, but we no
|
||||||
# longer have any consistency check for this since it is not important
|
# longer have any consistency check for this since it is not important
|
||||||
@ -2334,6 +2334,11 @@ $td->runtest("C API: no recovery",
|
|||||||
$td->EXIT_STATUS => 0},
|
$td->EXIT_STATUS => 0},
|
||||||
$td->NORMALIZE_NEWLINES);
|
$td->NORMALIZE_NEWLINES);
|
||||||
|
|
||||||
|
$td->runtest("integer type checks",
|
||||||
|
{$td->COMMAND => "test_driver 62 minimal.pdf"},
|
||||||
|
{$td->STRING => "test 62 done\n", $td->EXIT_STATUS => 0},
|
||||||
|
$td->NORMALIZE_NEWLINES);
|
||||||
|
|
||||||
show_ntests();
|
show_ntests();
|
||||||
# ----------
|
# ----------
|
||||||
$td->notify("--- Recovery Tests ---");
|
$td->notify("--- Recovery Tests ---");
|
||||||
|
@ -24,6 +24,7 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
#include <limits.h>
|
||||||
#include <map>
|
#include <map>
|
||||||
|
|
||||||
static char const* whoami = 0;
|
static char const* whoami = 0;
|
||||||
@ -189,21 +190,35 @@ static void read_file_into_memory(
|
|||||||
throw std::runtime_error(
|
throw std::runtime_error(
|
||||||
std::string("failure reading file ") + filename +
|
std::string("failure reading file ") + filename +
|
||||||
" into memory: read " +
|
" into memory: read " +
|
||||||
QUtil::int_to_string(bytes_read) + "; wanted " +
|
QUtil::uint_to_string(bytes_read) + "; wanted " +
|
||||||
QUtil::int_to_string(size));
|
QUtil::uint_to_string(size));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
throw std::logic_error(
|
throw std::logic_error(
|
||||||
std::string("premature eof reading file ") + filename +
|
std::string("premature eof reading file ") + filename +
|
||||||
" into memory: read " +
|
" into memory: read " +
|
||||||
QUtil::int_to_string(bytes_read) + "; wanted " +
|
QUtil::uint_to_string(bytes_read) + "; wanted " +
|
||||||
QUtil::int_to_string(size));
|
QUtil::uint_to_string(size));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fclose(f);
|
fclose(f);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define assert_compare_numbers(expected, expr) \
|
||||||
|
compare_numbers(#expr, expected, expr)
|
||||||
|
|
||||||
|
template <typename T1, typename T2>
|
||||||
|
static void compare_numbers(
|
||||||
|
char const* description, T1 const& expected, T2 const& actual)
|
||||||
|
{
|
||||||
|
if (expected != actual)
|
||||||
|
{
|
||||||
|
std::cerr << description << ": expected = " << expected
|
||||||
|
<< "; actual = " << actual << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void runtest(int n, char const* filename1, char const* arg2)
|
void runtest(int n, char const* filename1, char const* arg2)
|
||||||
{
|
{
|
||||||
// Most tests here are crafted to work on specific files. Look at
|
// Most tests here are crafted to work on specific files. Look at
|
||||||
@ -2090,6 +2105,31 @@ void runtest(int n, char const* filename1, char const* arg2)
|
|||||||
std::cout << "Caught runtime_error as expected" << std::endl;
|
std::cout << "Caught runtime_error as expected" << std::endl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (n == 62)
|
||||||
|
{
|
||||||
|
// Test int size checks. This test will fail if int and long
|
||||||
|
// long are the same size.
|
||||||
|
QPDFObjectHandle t = pdf.getTrailer();
|
||||||
|
unsigned long long q1_l = 3L * INT_MAX;
|
||||||
|
long long q1 = static_cast<long long>(q1_l);
|
||||||
|
long long q2_l = 3L * INT_MIN;
|
||||||
|
long long q2 = static_cast<long long>(q2_l);
|
||||||
|
unsigned int q3_i = UINT_MAX;
|
||||||
|
long long q3 = static_cast<long long>(q3_i);
|
||||||
|
t.replaceKey("/Q1", QPDFObjectHandle::newInteger(q1));
|
||||||
|
t.replaceKey("/Q2", QPDFObjectHandle::newInteger(q2));
|
||||||
|
t.replaceKey("/Q3", QPDFObjectHandle::newInteger(q3));
|
||||||
|
assert_compare_numbers(q1, t.getKey("/Q1").getIntValue());
|
||||||
|
assert_compare_numbers(q1_l, t.getKey("/Q1").getUIntValue());
|
||||||
|
assert_compare_numbers(INT_MAX, t.getKey("/Q1").getIntValueAsInt());
|
||||||
|
assert_compare_numbers(UINT_MAX, t.getKey("/Q1").getUIntValueAsUInt());
|
||||||
|
assert_compare_numbers(q2_l, t.getKey("/Q2").getIntValue());
|
||||||
|
assert_compare_numbers(0U, t.getKey("/Q2").getUIntValue());
|
||||||
|
assert_compare_numbers(INT_MIN, t.getKey("/Q2").getIntValueAsInt());
|
||||||
|
assert_compare_numbers(0U, t.getKey("/Q2").getUIntValueAsUInt());
|
||||||
|
assert_compare_numbers(INT_MAX, t.getKey("/Q3").getIntValueAsInt());
|
||||||
|
assert_compare_numbers(UINT_MAX, t.getKey("/Q3").getUIntValueAsUInt());
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
throw std::runtime_error(std::string("invalid test ") +
|
throw std::runtime_error(std::string("invalid test ") +
|
||||||
|
Loading…
Reference in New Issue
Block a user