aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJay Berkenbilt <ejb@ql.org>2022-05-15 20:56:04 +0200
committerJay Berkenbilt <ejb@ql.org>2022-05-16 19:39:26 +0200
commit60ec94a7c35ff3f7153c99deff29afef91500622 (patch)
tree91de8c310c6c0f8e5803d6b3ede4f00e5f3048ed
parent173b944ef8f1dd3f971a6089a52fcd1ae07ca8f1 (diff)
downloadqpdf-60ec94a7c35ff3f7153c99deff29afef91500622.tar.zst
Add QUtil::is_long_long
-rw-r--r--ChangeLog5
-rw-r--r--include/qpdf/QUtil.hh7
-rw-r--r--libqpdf/QUtil.cc13
-rw-r--r--libtests/qtest/qutil/qutil.out2
-rw-r--r--libtests/qutil.cc25
5 files changed, 52 insertions, 0 deletions
diff --git a/ChangeLog b/ChangeLog
index 8cf93186..a194440a 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,8 @@
+2022-05-15 Jay Berkenbilt <ejb@ql.org>
+
+ * Add QUtil::is_long_long to test whether a string can be
+ converted to a long long and back without loss of information.
+
2022-05-04 Jay Berkenbilt <ejb@ql.org>
* JSON: add a new "blob" type that takes a function to write data
diff --git a/include/qpdf/QUtil.hh b/include/qpdf/QUtil.hh
index 8b2b5ff8..5d33b2a5 100644
--- a/include/qpdf/QUtil.hh
+++ b/include/qpdf/QUtil.hh
@@ -65,6 +65,13 @@ namespace QUtil
QPDF_DLL
unsigned int string_to_uint(char const* str);
+ // Returns true if this exactly represents a long long. The
+ // determination is made by converting the string to a long long,
+ // then converting the result back to a string, and then comparing
+ // that result with the original string.
+ QPDF_DLL
+ bool is_long_long(char const* str);
+
// Pipeline's write method wants unsigned char*, but we often have
// some other type of string. These methods do combinations of
// const_cast and reinterpret_cast to give us an unsigned char*.
diff --git a/libqpdf/QUtil.cc b/libqpdf/QUtil.cc
index 22962199..8edfadae 100644
--- a/libqpdf/QUtil.cc
+++ b/libqpdf/QUtil.cc
@@ -467,6 +467,19 @@ QUtil::string_to_uint(char const* str)
return QIntC::to_uint(string_to_ull(str));
}
+bool
+QUtil::is_long_long(char const* str)
+{
+ try {
+ auto i1 = string_to_ll(str);
+ std::string s1 = int_to_string(i1);
+ return str == s1;
+ } catch (std::exception&) {
+ // overflow or other error
+ }
+ return false;
+}
+
unsigned char*
QUtil::unsigned_char_pointer(std::string const& str)
{
diff --git a/libtests/qtest/qutil/qutil.out b/libtests/qtest/qutil/qutil.out
index e9c53170..d91acba9 100644
--- a/libtests/qtest/qutil/qutil.out
+++ b/libtests/qtest/qutil/qutil.out
@@ -129,3 +129,5 @@ delete file
D:20210209144925-05'00'
D:20210210011925+05'30'
D:20210209191925Z
+---- is_long_long
+done
diff --git a/libtests/qutil.cc b/libtests/qutil.cc
index f79f9a3f..ea0aece7 100644
--- a/libtests/qutil.cc
+++ b/libtests/qutil.cc
@@ -676,6 +676,29 @@ timestamp_test()
QUtil::qpdf_time_to_pdf_time(QUtil::get_current_qpdf_time())));
}
+void
+is_long_long_test()
+{
+ auto check = [](char const* s, bool v) {
+ if (QUtil::is_long_long(s) != v) {
+ std::cout << "failed: " << s << std::endl;
+ }
+ };
+ check("12312312", true);
+ check("12312312.34", false);
+ check("-12312312", true);
+ check("-12312312.34", false);
+ check("1e2", false);
+ check("9223372036854775807", true);
+ check("9223372036854775808", false);
+ check("-9223372036854775808", true);
+ check("-9223372036854775809", false);
+ check("123123123123123123123123123123123123", false);
+ check("potato", false);
+ check("0123", false);
+ std::cout << "done" << std::endl;
+}
+
int
main(int argc, char* argv[])
{
@@ -710,6 +733,8 @@ main(int argc, char* argv[])
rename_delete_test();
std::cout << "---- timestamp" << std::endl;
timestamp_test();
+ std::cout << "---- is_long_long" << std::endl;
+ is_long_long_test();
} catch (std::exception& e) {
std::cout << "unexpected exception: " << e.what() << std::endl;
}