mirror of
https://github.com/qpdf/qpdf.git
synced 2024-06-04 11:20:53 +00:00
Rewrite QUtil::int_to_string and QUtil::double_to_string
Make them safer by avoiding any internal limits and replacing sprintf with std::ostringstream.
This commit is contained in:
parent
ed19516aa7
commit
8be8277613
|
@ -1,3 +1,9 @@
|
||||||
|
2013-02-26 Jay Berkenbilt <ejb@ql.org>
|
||||||
|
|
||||||
|
* Rewrite QUtil::int_to_string and QUtil::double_to_string to
|
||||||
|
remove internal length limits but to remain backward compatible
|
||||||
|
with the old versions for valid inputs.
|
||||||
|
|
||||||
2013-02-23 Jay Berkenbilt <ejb@ql.org>
|
2013-02-23 Jay Berkenbilt <ejb@ql.org>
|
||||||
|
|
||||||
* Bug fix: properly handle overridden compressed objects. When
|
* Bug fix: properly handle overridden compressed objects. When
|
||||||
|
|
18
configure.ac
18
configure.ac
|
@ -68,24 +68,6 @@ AC_CHECK_FUNCS([fseeko64])
|
||||||
AC_TYPE_UINT16_T
|
AC_TYPE_UINT16_T
|
||||||
AC_TYPE_UINT32_T
|
AC_TYPE_UINT32_T
|
||||||
|
|
||||||
AC_MSG_CHECKING(for whether printf supports %ll)
|
|
||||||
AC_COMPILE_IFELSE([AC_LANG_SOURCE([[
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <sys/types.h>
|
|
||||||
int
|
|
||||||
main()
|
|
||||||
{
|
|
||||||
long long a = 160591605916059ll;
|
|
||||||
char t[50];
|
|
||||||
sprintf(t, "%lld", a);
|
|
||||||
}
|
|
||||||
]])],[qpdf_PRINTF_LL=yes],[qpdf_PRINTF_LL=no])
|
|
||||||
AC_MSG_RESULT($qpdf_PRINTF_LL)
|
|
||||||
if test "$qpdf_PRINTF_LL" = "yes"; then
|
|
||||||
AC_DEFINE([HAVE_PRINTF_LL], [1], [Whether printf supports %ll])
|
|
||||||
fi
|
|
||||||
|
|
||||||
AC_CHECK_FUNCS(random)
|
AC_CHECK_FUNCS(random)
|
||||||
|
|
||||||
# Check if LD supports linker scripts, and define conditional
|
# Check if LD supports linker scripts, and define conditional
|
||||||
|
|
|
@ -4,6 +4,9 @@
|
||||||
#include <qpdf/QUtil.hh>
|
#include <qpdf/QUtil.hh>
|
||||||
#include <qpdf/PointerHolder.hh>
|
#include <qpdf/PointerHolder.hh>
|
||||||
|
|
||||||
|
#include <cmath>
|
||||||
|
#include <iomanip>
|
||||||
|
#include <sstream>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
|
@ -19,72 +22,41 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
std::string
|
std::string
|
||||||
QUtil::int_to_string(long long num, int fullpad)
|
QUtil::int_to_string(long long num, int length)
|
||||||
{
|
{
|
||||||
// This routine will need to be recompiled if an int can be longer than
|
// Backward compatibility -- this function used to use sprintf
|
||||||
// 49 digits.
|
// with %0*d, so we interpret length such that a negative value
|
||||||
char t[50];
|
// appends spaces and a positive value prepends zeroes.
|
||||||
|
std::ostringstream buf;
|
||||||
// -2 or -1 to leave space for the possible negative sign and for NUL...
|
buf << num;
|
||||||
if (abs(fullpad) > sizeof(t) - ((num < 0)?2:1))
|
std::string result;
|
||||||
|
if ((length > 0) &&
|
||||||
|
(buf.str().length() < static_cast<size_t>(length)))
|
||||||
{
|
{
|
||||||
throw std::logic_error("Util::int_to_string has been called with "
|
result.append(length - buf.str().length(), '0');
|
||||||
"a padding value greater than its internal "
|
|
||||||
"limit");
|
|
||||||
}
|
}
|
||||||
|
result += buf.str();
|
||||||
#ifdef HAVE_PRINTF_LL
|
if ((length < 0) && (buf.str().length() < static_cast<size_t>(-length)))
|
||||||
# define PRINTF_LL "ll"
|
|
||||||
#else
|
|
||||||
# define PRINTF_LL "l"
|
|
||||||
#endif
|
|
||||||
if (fullpad)
|
|
||||||
{
|
{
|
||||||
sprintf(t, "%0*" PRINTF_LL "d", fullpad, num);
|
result.append(-length - buf.str().length(), ' ');
|
||||||
}
|
}
|
||||||
else
|
return result;
|
||||||
{
|
|
||||||
sprintf(t, "%" PRINTF_LL "d", num);
|
|
||||||
}
|
|
||||||
#undef PRINTF_LL
|
|
||||||
|
|
||||||
return std::string(t);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string
|
std::string
|
||||||
QUtil::double_to_string(double num, int decimal_places)
|
QUtil::double_to_string(double num, int decimal_places)
|
||||||
{
|
{
|
||||||
// This routine will need to be recompiled if a double can be longer than
|
// Backward compatibility -- this code used to use sprintf and
|
||||||
// 99 digits.
|
// treated decimal_places <= 0 to mean to use the default, which
|
||||||
char t[100];
|
// was six decimal places. Also sprintf with %*.f interprents the
|
||||||
|
// length as fixed point rather than significant figures.
|
||||||
std::string lhs = int_to_string(static_cast<int>(num));
|
if (decimal_places <= 0)
|
||||||
|
|
||||||
// lhs.length() gives us the length of the part on the right hand
|
|
||||||
// side of the dot + 1 for the dot + decimal_places: total size of
|
|
||||||
// the required string. -1 on the sizeof side to allow for NUL at
|
|
||||||
// the end.
|
|
||||||
//
|
|
||||||
// If decimal_places <= 0, it is as if no precision was provided
|
|
||||||
// so trust the buffer is big enough. The following test will
|
|
||||||
// always pass in those cases.
|
|
||||||
if (decimal_places + 1 + static_cast<int>(lhs.length()) >
|
|
||||||
static_cast<int>(sizeof(t)) - 1)
|
|
||||||
{
|
{
|
||||||
throw std::logic_error("Util::double_to_string has been called with "
|
decimal_places = 6;
|
||||||
"a number and a decimal places specification "
|
|
||||||
"that would break an internal limit");
|
|
||||||
}
|
}
|
||||||
|
std::ostringstream buf;
|
||||||
if (decimal_places)
|
buf << std::setprecision(decimal_places) << std::fixed << num;
|
||||||
{
|
return buf.str();
|
||||||
sprintf(t, "%.*f", decimal_places, num);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
sprintf(t, "%f", num);
|
|
||||||
}
|
|
||||||
return std::string(t);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
long long
|
long long
|
||||||
|
|
|
@ -4,11 +4,10 @@
|
||||||
3.141590
|
3.141590
|
||||||
3.142
|
3.142
|
||||||
1000.123000
|
1000.123000
|
||||||
exception 1: Util::int_to_string has been called with a padding value greater than its internal limit
|
0.12340
|
||||||
exception 2: Util::int_to_string has been called with a padding value greater than its internal limit
|
0.00012
|
||||||
exception 3: Util::int_to_string has been called with a padding value greater than its internal limit
|
0.12346
|
||||||
exception 4: Util::double_to_string has been called with a number and a decimal places specification that would break an internal limit
|
0.00012
|
||||||
exception 5: Util::double_to_string has been called with a number and a decimal places specification that would break an internal limit
|
|
||||||
one
|
one
|
||||||
7
|
7
|
||||||
compare okay
|
compare okay
|
||||||
|
|
|
@ -19,58 +19,11 @@ void string_conversion_test()
|
||||||
<< QUtil::int_to_string(16059, -7) << std::endl
|
<< QUtil::int_to_string(16059, -7) << std::endl
|
||||||
<< QUtil::double_to_string(3.14159) << std::endl
|
<< QUtil::double_to_string(3.14159) << std::endl
|
||||||
<< QUtil::double_to_string(3.14159, 3) << std::endl
|
<< QUtil::double_to_string(3.14159, 3) << std::endl
|
||||||
<< QUtil::double_to_string(1000.123, -1024) << std::endl;
|
<< QUtil::double_to_string(1000.123, -1024) << std::endl
|
||||||
|
<< QUtil::double_to_string(.1234, 5) << std::endl
|
||||||
try
|
<< QUtil::double_to_string(.0001234, 5) << std::endl
|
||||||
{
|
<< QUtil::double_to_string(.123456, 5) << std::endl
|
||||||
// int_to_string bounds error
|
<< QUtil::double_to_string(.000123456, 5) << std::endl;
|
||||||
std::cout << QUtil::int_to_string(1, 50) << std::endl;
|
|
||||||
}
|
|
||||||
catch (std::logic_error &e)
|
|
||||||
{
|
|
||||||
std::cout << "exception 1: " << e.what() << std::endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
// QUtil::int_to_string bounds error
|
|
||||||
std::cout << QUtil::int_to_string(1, -50) << std::endl;
|
|
||||||
}
|
|
||||||
catch (std::logic_error& e)
|
|
||||||
{
|
|
||||||
std::cout << "exception 2: " << e.what() << std::endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
// QUtil::int_to_string bounds error
|
|
||||||
std::cout << QUtil::int_to_string(-1, 49) << std::endl;
|
|
||||||
}
|
|
||||||
catch (std::logic_error& e)
|
|
||||||
{
|
|
||||||
std::cout << "exception 3: " << e.what() << std::endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
// QUtil::double_to_string bounds error
|
|
||||||
std::cout << QUtil::double_to_string(3.14159, 1024) << std::endl;
|
|
||||||
}
|
|
||||||
catch (std::logic_error& e)
|
|
||||||
{
|
|
||||||
std::cout << "exception 4: " << e.what() << std::endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
// QUtil::double_to_string bounds error
|
|
||||||
std::cout << QUtil::double_to_string(1000.0, 95) << std::endl;
|
|
||||||
}
|
|
||||||
catch (std::logic_error& e)
|
|
||||||
{
|
|
||||||
std::cout << "exception 5: " << e.what() << std::endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string embedded_null = "one";
|
std::string embedded_null = "one";
|
||||||
embedded_null += '\0';
|
embedded_null += '\0';
|
||||||
|
|
Loading…
Reference in New Issue
Block a user