Commit 60ec94a7c35ff3f7153c99deff29afef91500622

Authored by Jay Berkenbilt
1 parent 173b944e

Add QUtil::is_long_long

ChangeLog
  1 +2022-05-15 Jay Berkenbilt <ejb@ql.org>
  2 +
  3 + * Add QUtil::is_long_long to test whether a string can be
  4 + converted to a long long and back without loss of information.
  5 +
1 2022-05-04 Jay Berkenbilt <ejb@ql.org> 6 2022-05-04 Jay Berkenbilt <ejb@ql.org>
2 7
3 * JSON: add a new "blob" type that takes a function to write data 8 * JSON: add a new "blob" type that takes a function to write data
include/qpdf/QUtil.hh
@@ -65,6 +65,13 @@ namespace QUtil @@ -65,6 +65,13 @@ namespace QUtil
65 QPDF_DLL 65 QPDF_DLL
66 unsigned int string_to_uint(char const* str); 66 unsigned int string_to_uint(char const* str);
67 67
  68 + // Returns true if this exactly represents a long long. The
  69 + // determination is made by converting the string to a long long,
  70 + // then converting the result back to a string, and then comparing
  71 + // that result with the original string.
  72 + QPDF_DLL
  73 + bool is_long_long(char const* str);
  74 +
68 // Pipeline's write method wants unsigned char*, but we often have 75 // Pipeline's write method wants unsigned char*, but we often have
69 // some other type of string. These methods do combinations of 76 // some other type of string. These methods do combinations of
70 // const_cast and reinterpret_cast to give us an unsigned char*. 77 // const_cast and reinterpret_cast to give us an unsigned char*.
libqpdf/QUtil.cc
@@ -467,6 +467,19 @@ QUtil::string_to_uint(char const* str) @@ -467,6 +467,19 @@ QUtil::string_to_uint(char const* str)
467 return QIntC::to_uint(string_to_ull(str)); 467 return QIntC::to_uint(string_to_ull(str));
468 } 468 }
469 469
  470 +bool
  471 +QUtil::is_long_long(char const* str)
  472 +{
  473 + try {
  474 + auto i1 = string_to_ll(str);
  475 + std::string s1 = int_to_string(i1);
  476 + return str == s1;
  477 + } catch (std::exception&) {
  478 + // overflow or other error
  479 + }
  480 + return false;
  481 +}
  482 +
470 unsigned char* 483 unsigned char*
471 QUtil::unsigned_char_pointer(std::string const& str) 484 QUtil::unsigned_char_pointer(std::string const& str)
472 { 485 {
libtests/qtest/qutil/qutil.out
@@ -129,3 +129,5 @@ delete file @@ -129,3 +129,5 @@ delete file
129 D:20210209144925-05'00' 129 D:20210209144925-05'00'
130 D:20210210011925+05'30' 130 D:20210210011925+05'30'
131 D:20210209191925Z 131 D:20210209191925Z
  132 +---- is_long_long
  133 +done
libtests/qutil.cc
@@ -676,6 +676,29 @@ timestamp_test() @@ -676,6 +676,29 @@ timestamp_test()
676 QUtil::qpdf_time_to_pdf_time(QUtil::get_current_qpdf_time()))); 676 QUtil::qpdf_time_to_pdf_time(QUtil::get_current_qpdf_time())));
677 } 677 }
678 678
  679 +void
  680 +is_long_long_test()
  681 +{
  682 + auto check = [](char const* s, bool v) {
  683 + if (QUtil::is_long_long(s) != v) {
  684 + std::cout << "failed: " << s << std::endl;
  685 + }
  686 + };
  687 + check("12312312", true);
  688 + check("12312312.34", false);
  689 + check("-12312312", true);
  690 + check("-12312312.34", false);
  691 + check("1e2", false);
  692 + check("9223372036854775807", true);
  693 + check("9223372036854775808", false);
  694 + check("-9223372036854775808", true);
  695 + check("-9223372036854775809", false);
  696 + check("123123123123123123123123123123123123", false);
  697 + check("potato", false);
  698 + check("0123", false);
  699 + std::cout << "done" << std::endl;
  700 +}
  701 +
679 int 702 int
680 main(int argc, char* argv[]) 703 main(int argc, char* argv[])
681 { 704 {
@@ -710,6 +733,8 @@ main(int argc, char* argv[]) @@ -710,6 +733,8 @@ main(int argc, char* argv[])
710 rename_delete_test(); 733 rename_delete_test();
711 std::cout << "---- timestamp" << std::endl; 734 std::cout << "---- timestamp" << std::endl;
712 timestamp_test(); 735 timestamp_test();
  736 + std::cout << "---- is_long_long" << std::endl;
  737 + is_long_long_test();
713 } catch (std::exception& e) { 738 } catch (std::exception& e) {
714 std::cout << "unexpected exception: " << e.what() << std::endl; 739 std::cout << "unexpected exception: " << e.what() << std::endl;
715 } 740 }