From 8be827761347b7a0a4ce6e7bdfa6fd4585606b21 Mon Sep 17 00:00:00 2001 From: Jay Berkenbilt Date: Tue, 26 Feb 2013 12:31:00 -0500 Subject: Rewrite QUtil::int_to_string and QUtil::double_to_string Make them safer by avoiding any internal limits and replacing sprintf with std::ostringstream. --- libqpdf/QUtil.cc | 80 ++++++++++++++++++-------------------------------------- 1 file changed, 26 insertions(+), 54 deletions(-) (limited to 'libqpdf') diff --git a/libqpdf/QUtil.cc b/libqpdf/QUtil.cc index 9549bfa1..967e832c 100644 --- a/libqpdf/QUtil.cc +++ b/libqpdf/QUtil.cc @@ -4,6 +4,9 @@ #include #include +#include +#include +#include #include #include #include @@ -19,72 +22,41 @@ #endif 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 - // 49 digits. - char t[50]; - - // -2 or -1 to leave space for the possible negative sign and for NUL... - if (abs(fullpad) > sizeof(t) - ((num < 0)?2:1)) - { - throw std::logic_error("Util::int_to_string has been called with " - "a padding value greater than its internal " - "limit"); - } - -#ifdef HAVE_PRINTF_LL -# define PRINTF_LL "ll" -#else -# define PRINTF_LL "l" -#endif - if (fullpad) + // Backward compatibility -- this function used to use sprintf + // with %0*d, so we interpret length such that a negative value + // appends spaces and a positive value prepends zeroes. + std::ostringstream buf; + buf << num; + std::string result; + if ((length > 0) && + (buf.str().length() < static_cast(length))) { - sprintf(t, "%0*" PRINTF_LL "d", fullpad, num); + result.append(length - buf.str().length(), '0'); } - else + result += buf.str(); + if ((length < 0) && (buf.str().length() < static_cast(-length))) { - sprintf(t, "%" PRINTF_LL "d", num); + result.append(-length - buf.str().length(), ' '); } -#undef PRINTF_LL - - return std::string(t); + return result; } std::string QUtil::double_to_string(double num, int decimal_places) { - // This routine will need to be recompiled if a double can be longer than - // 99 digits. - char t[100]; - - std::string lhs = int_to_string(static_cast(num)); - - // 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(lhs.length()) > - static_cast(sizeof(t)) - 1) - { - throw std::logic_error("Util::double_to_string has been called with " - "a number and a decimal places specification " - "that would break an internal limit"); - } - - if (decimal_places) - { - sprintf(t, "%.*f", decimal_places, num); - } - else + // Backward compatibility -- this code used to use sprintf and + // treated decimal_places <= 0 to mean to use the default, which + // was six decimal places. Also sprintf with %*.f interprents the + // length as fixed point rather than significant figures. + if (decimal_places <= 0) { - sprintf(t, "%f", num); + decimal_places = 6; } - return std::string(t); + std::ostringstream buf; + buf << std::setprecision(decimal_places) << std::fixed << num; + return buf.str(); } long long -- cgit v1.2.3-54-g00ecf