mirror of
https://github.com/qpdf/qpdf.git
synced 2024-12-22 02:49:00 +00:00
QUtil: add unsigned int/string functions
This commit is contained in:
parent
a66828caff
commit
42306e2ff8
@ -1,5 +1,9 @@
|
||||
2019-06-20 Jay Berkenbilt <ejb@ql.org>
|
||||
|
||||
* Add functions to QUtil to convert unsigned integers to strings,
|
||||
avoiding implicit conversion between unsigned and signed integer
|
||||
types.
|
||||
|
||||
* Add QIC.hh, containing integer type converters that do range
|
||||
checking.
|
||||
|
||||
|
@ -40,8 +40,12 @@ namespace QUtil
|
||||
QPDF_DLL
|
||||
std::string int_to_string(long long, int length = 0);
|
||||
QPDF_DLL
|
||||
std::string uint_to_string(unsigned long long, int length = 0);
|
||||
QPDF_DLL
|
||||
std::string int_to_string_base(long long, int base, int length = 0);
|
||||
QPDF_DLL
|
||||
std::string uint_to_string_base(unsigned long long, int base, int length = 0);
|
||||
QPDF_DLL
|
||||
std::string double_to_string(double, int decimal_places = 0);
|
||||
|
||||
// These string to number methods throw std::runtime_error on
|
||||
@ -50,6 +54,10 @@ namespace QUtil
|
||||
long long string_to_ll(char const* str);
|
||||
QPDF_DLL
|
||||
int string_to_int(char const* str);
|
||||
QPDF_DLL
|
||||
unsigned long long string_to_ull(char const* str);
|
||||
QPDF_DLL
|
||||
unsigned int string_to_uint(char const* str);
|
||||
|
||||
// Pipeline's write method wants unsigned char*, but we often have
|
||||
// some other type of string. These methods do combinations of
|
||||
|
100
libqpdf/QUtil.cc
100
libqpdf/QUtil.cc
@ -9,6 +9,7 @@
|
||||
#include <qpdf/SecureRandomDataProvider.hh>
|
||||
#include <qpdf/QPDFSystemError.hh>
|
||||
#include <qpdf/QTC.hh>
|
||||
#include <qpdf/QIntC.hh>
|
||||
|
||||
#include <cmath>
|
||||
#include <iomanip>
|
||||
@ -233,14 +234,10 @@ static unsigned short mac_roman_to_unicode[] = {
|
||||
0x02c7, // 0xff
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
static
|
||||
std::string
|
||||
QUtil::int_to_string(long long num, int length)
|
||||
{
|
||||
return int_to_string_base(num, 10, length);
|
||||
}
|
||||
|
||||
std::string
|
||||
QUtil::int_to_string_base(long long num, int base, int length)
|
||||
int_to_string_base_internal(T num, int base, int length)
|
||||
{
|
||||
// Backward compatibility -- int_to_string, which calls this
|
||||
// function, used to use sprintf with %0*d, so we interpret length
|
||||
@ -255,18 +252,42 @@ QUtil::int_to_string_base(long long num, int base, int length)
|
||||
buf << std::setbase(base) << std::nouppercase << num;
|
||||
std::string result;
|
||||
if ((length > 0) &&
|
||||
(buf.str().length() < static_cast<size_t>(length)))
|
||||
(buf.str().length() < QIntC::to_size(length)))
|
||||
{
|
||||
result.append(length - buf.str().length(), '0');
|
||||
}
|
||||
result += buf.str();
|
||||
if ((length < 0) && (buf.str().length() < static_cast<size_t>(-length)))
|
||||
if ((length < 0) && (buf.str().length() < QIntC::to_size(-length)))
|
||||
{
|
||||
result.append(-length - buf.str().length(), ' ');
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string
|
||||
QUtil::int_to_string(long long num, int length)
|
||||
{
|
||||
return int_to_string_base(num, 10, length);
|
||||
}
|
||||
|
||||
std::string
|
||||
QUtil::uint_to_string(unsigned long long num, int length)
|
||||
{
|
||||
return int_to_string_base(num, 10, length);
|
||||
}
|
||||
|
||||
std::string
|
||||
QUtil::int_to_string_base(long long num, int base, int length)
|
||||
{
|
||||
return int_to_string_base_internal(num, base, length);
|
||||
}
|
||||
|
||||
std::string
|
||||
QUtil::uint_to_string_base(unsigned long long num, int base, int length)
|
||||
{
|
||||
return int_to_string_base_internal(num, base, length);
|
||||
}
|
||||
|
||||
std::string
|
||||
QUtil::double_to_string(double num, int decimal_places)
|
||||
{
|
||||
@ -294,7 +315,7 @@ QUtil::string_to_ll(char const* str)
|
||||
#endif
|
||||
if (errno == ERANGE)
|
||||
{
|
||||
throw std::runtime_error(
|
||||
throw std::range_error(
|
||||
std::string("overflow/underflow converting ") + str
|
||||
+ " to 64-bit integer");
|
||||
}
|
||||
@ -304,24 +325,47 @@ QUtil::string_to_ll(char const* str)
|
||||
int
|
||||
QUtil::string_to_int(char const* str)
|
||||
{
|
||||
// QIntC::to_int does range checking
|
||||
return QIntC::to_int(string_to_ll(str));
|
||||
}
|
||||
|
||||
unsigned long long
|
||||
QUtil::string_to_ull(char const* str)
|
||||
{
|
||||
char const* p = str;
|
||||
while (*p && is_space(*p))
|
||||
{
|
||||
++p;
|
||||
}
|
||||
if (*p == '-')
|
||||
{
|
||||
throw std::runtime_error(
|
||||
std::string("underflow converting ") + str
|
||||
+ " to 64-bit unsigned integer");
|
||||
}
|
||||
|
||||
errno = 0;
|
||||
long long_val = strtol(str, 0, 10);
|
||||
#ifdef _MSC_VER
|
||||
unsigned long long result = _strtoui64(str, 0, 10);
|
||||
#else
|
||||
unsigned long long result = strtoull(str, 0, 10);
|
||||
#endif
|
||||
if (errno == ERANGE)
|
||||
{
|
||||
throw std::runtime_error(
|
||||
std::string("overflow/underflow converting ") + str
|
||||
+ " to long integer");
|
||||
}
|
||||
int result = static_cast<int>(long_val);
|
||||
if (static_cast<long>(result) != long_val)
|
||||
{
|
||||
throw std::runtime_error(
|
||||
std::string("overflow/underflow converting ") + str
|
||||
+ " to integer");
|
||||
std::string("overflow converting ") + str
|
||||
+ " to 64-bit unsigned integer");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
unsigned int
|
||||
QUtil::string_to_uint(char const* str)
|
||||
{
|
||||
// QIntC::to_uint does range checking
|
||||
return QIntC::to_uint(string_to_ull(str));
|
||||
}
|
||||
|
||||
unsigned char*
|
||||
QUtil::unsigned_char_pointer(std::string const& str)
|
||||
{
|
||||
@ -412,14 +456,18 @@ int
|
||||
QUtil::seek(FILE* stream, qpdf_offset_t offset, int whence)
|
||||
{
|
||||
#if HAVE_FSEEKO
|
||||
return fseeko(stream, static_cast<off_t>(offset), whence);
|
||||
return fseeko(stream,
|
||||
QIntC::IntConverter<qpdf_offset_t, off_t>::convert(offset),
|
||||
whence);
|
||||
#elif HAVE_FSEEKO64
|
||||
return fseeko64(stream, offset, whence);
|
||||
#else
|
||||
# if defined _MSC_VER || defined __BORLANDC__
|
||||
return _fseeki64(stream, offset, whence);
|
||||
# else
|
||||
return fseek(stream, static_cast<long>(offset), whence);
|
||||
return fseek(stream,
|
||||
QIntC::IntConverter<qpdf_offset_t, long>(offset),
|
||||
whence);
|
||||
# endif
|
||||
#endif
|
||||
}
|
||||
@ -428,14 +476,14 @@ qpdf_offset_t
|
||||
QUtil::tell(FILE* stream)
|
||||
{
|
||||
#if HAVE_FSEEKO
|
||||
return static_cast<qpdf_offset_t>(ftello(stream));
|
||||
return QIntC::to_offset(ftello(stream));
|
||||
#elif HAVE_FSEEKO64
|
||||
return static_cast<qpdf_offset_t>(ftello64(stream));
|
||||
return QIntC::to_offset(ftello64(stream));
|
||||
#else
|
||||
# if defined _MSC_VER || defined __BORLANDC__
|
||||
return _ftelli64(stream);
|
||||
# else
|
||||
return static_cast<qpdf_offset_t>(ftell(stream));
|
||||
return QIntC::to_offset(ftell(stream));
|
||||
# endif
|
||||
#endif
|
||||
}
|
||||
@ -508,7 +556,7 @@ QUtil::hex_encode(std::string const& input)
|
||||
for (unsigned int i = 0; i < input.length(); ++i)
|
||||
{
|
||||
result += QUtil::int_to_string_base(
|
||||
static_cast<int>(static_cast<unsigned char>(input.at(i))), 16, 2);
|
||||
QIntC::to_int(static_cast<unsigned char>(input.at(i))), 16, 2);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
@ -17,12 +17,17 @@ one
|
||||
compare okay
|
||||
-2147483648 to int: PASSED
|
||||
2147483647 to int: PASSED
|
||||
2147483648 to int threw: PASSED
|
||||
-2147483649 to int threw: PASSED
|
||||
9999999999999999999999999 to int threw: PASSED
|
||||
2147483648 to int threw (integer out of range converting 2147483648 from a 8-byte signed type to a 4-byte signed type): PASSED
|
||||
-2147483649 to int threw (integer out of range converting -2147483649 from a 8-byte signed type to a 4-byte signed type): PASSED
|
||||
9999999999999999999999999 to int threw (overflow/underflow converting 9999999999999999999999999 to 64-bit integer): PASSED
|
||||
2147483648 to int: PASSED
|
||||
-2147483649 to int: PASSED
|
||||
99999999999999999999999999999999999999999999999999 to int threw: PASSED
|
||||
99999999999999999999999999999999999999999999999999 to int threw (overflow/underflow converting 99999999999999999999999999999999999999999999999999 to 64-bit integer): PASSED
|
||||
16059 to int: PASSED
|
||||
-16059 to int threw (underflow converting -16059 to 64-bit unsigned integer): PASSED
|
||||
9999999999 to int threw (integer out of range converting 9999999999 from a 8-byte unsigned type to a 4-byte unsigned type): PASSED
|
||||
16059 to int: PASSED
|
||||
-16059 to int threw (underflow converting -16059 to 64-bit unsigned integer): PASSED
|
||||
---- os wrapper
|
||||
before remove
|
||||
exception: remove file: No such file or directory
|
||||
|
@ -23,20 +23,22 @@ void test_to_number(char const* str, int_T wanted, bool error,
|
||||
bool threw = false;
|
||||
bool worked = false;
|
||||
int_T result = 0;
|
||||
std::string msg;
|
||||
try
|
||||
{
|
||||
result = fn(str);
|
||||
worked = (wanted == result);
|
||||
}
|
||||
catch (std::runtime_error const&)
|
||||
catch (std::runtime_error const& e)
|
||||
{
|
||||
threw = true;
|
||||
msg = e.what();
|
||||
}
|
||||
if (threw)
|
||||
{
|
||||
if (error)
|
||||
{
|
||||
std::cout << str << " to int threw: PASSED" << std::endl;
|
||||
std::cout << str << " to int threw (" << msg << "): PASSED" << std::endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -67,6 +69,16 @@ void test_to_ll(char const* str, long long wanted, bool error)
|
||||
test_to_number(str, wanted, error, QUtil::string_to_ll);
|
||||
}
|
||||
|
||||
void test_to_uint(char const* str, unsigned int wanted, bool error)
|
||||
{
|
||||
test_to_number(str, wanted, error, QUtil::string_to_uint);
|
||||
}
|
||||
|
||||
void test_to_ull(char const* str, unsigned long long wanted, bool error)
|
||||
{
|
||||
test_to_number(str, wanted, error, QUtil::string_to_ull);
|
||||
}
|
||||
|
||||
void string_conversion_test()
|
||||
{
|
||||
std::cout << QUtil::int_to_string(16059) << std::endl
|
||||
@ -105,6 +117,8 @@ void string_conversion_test()
|
||||
long long int_min_minus_1 = static_cast<long long>(INT_MIN) - 1;
|
||||
std::string int_max_plus_1_str = QUtil::int_to_string(int_max_plus_1);
|
||||
std::string int_min_minus_1_str = QUtil::int_to_string(int_min_minus_1);
|
||||
std::string small_positive = QUtil::uint_to_string(16059U);
|
||||
std::string small_negative = QUtil::int_to_string(-16059);
|
||||
test_to_int(int_min_str.c_str(), INT_MIN, false);
|
||||
test_to_int(int_max_str.c_str(), INT_MAX, false);
|
||||
test_to_int(int_max_plus_1_str.c_str(), 0, true);
|
||||
@ -113,6 +127,11 @@ void string_conversion_test()
|
||||
test_to_ll(int_max_plus_1_str.c_str(), int_max_plus_1, false);
|
||||
test_to_ll(int_min_minus_1_str.c_str(), int_min_minus_1, false);
|
||||
test_to_ll("99999999999999999999999999999999999999999999999999", 0, true);
|
||||
test_to_uint(small_positive.c_str(), 16059U, false);
|
||||
test_to_uint(small_negative.c_str(), 0, true);
|
||||
test_to_uint("9999999999", 0, true);
|
||||
test_to_ull(small_positive.c_str(), 16059U, false);
|
||||
test_to_ull(small_negative.c_str(), 0, true);
|
||||
}
|
||||
|
||||
void os_wrapper_test()
|
||||
@ -159,7 +178,7 @@ void getenv_test()
|
||||
static void print_utf8(unsigned long val)
|
||||
{
|
||||
std::string result = QUtil::toUTF8(val);
|
||||
std::cout << "0x" << QUtil::int_to_string_base(val, 16) << " ->";
|
||||
std::cout << "0x" << QUtil::uint_to_string_base(val, 16) << " ->";
|
||||
if (val < 0xfffe)
|
||||
{
|
||||
std::cout << " " << result;
|
||||
@ -199,7 +218,7 @@ void to_utf8_test()
|
||||
static void print_utf16(unsigned long val)
|
||||
{
|
||||
std::string result = QUtil::toUTF16(val);
|
||||
std::cout << "0x" << QUtil::int_to_string_base(val, 16) << " ->";
|
||||
std::cout << "0x" << QUtil::uint_to_string_base(val, 16) << " ->";
|
||||
for (std::string::iterator iter = result.begin();
|
||||
iter != result.end(); ++iter)
|
||||
{
|
||||
@ -249,7 +268,7 @@ void transcoding_test(std::string (*to_utf8)(std::string const&),
|
||||
std::string back;
|
||||
for (int i = 128; i <= last; ++i)
|
||||
{
|
||||
in.at(0) = static_cast<unsigned char>(i);
|
||||
in.at(0) = static_cast<char>(static_cast<unsigned char>(i));
|
||||
out = (*to_utf8)(in);
|
||||
std::string wanted = (out == "\xef\xbf\xbd") ? unknown : in;
|
||||
back = (*from_utf8)(out, '?');
|
||||
|
Loading…
Reference in New Issue
Block a user