Commit 67edbfd954a4249d6c78bd375294e4a5bbde3846

Authored by m-holger
1 parent fa8dd266

Un-inline QUtil functions

Add new private Util.hh header to define inline functions and expose as
ordinary functions in QUtil.
include/qpdf/QUtil.hh
@@ -190,7 +190,7 @@ namespace QUtil @@ -190,7 +190,7 @@ namespace QUtil
190 190
191 // Returns lower-case hex-encoded version of the char including a leading "#". 191 // Returns lower-case hex-encoded version of the char including a leading "#".
192 QPDF_DLL 192 QPDF_DLL
193 - inline std::string hex_encode_char(char); 193 + std::string hex_encode_char(char);
194 194
195 // Returns a string that is the result of decoding the input string. The input string may 195 // Returns a string that is the result of decoding the input string. The input string may
196 // consist of mixed case hexadecimal digits. Any characters that are not hexadecimal digits will 196 // consist of mixed case hexadecimal digits. Any characters that are not hexadecimal digits will
@@ -202,7 +202,7 @@ namespace QUtil @@ -202,7 +202,7 @@ namespace QUtil
202 // Decode a single hex digit into a char in the range 0 <= char < 16. Return a char >= 16 if 202 // Decode a single hex digit into a char in the range 0 <= char < 16. Return a char >= 16 if
203 // digit is not a valid hex digit. 203 // digit is not a valid hex digit.
204 QPDF_DLL 204 QPDF_DLL
205 - inline constexpr char hex_decode_char(char digit) noexcept; 205 + char hex_decode_char(char digit);
206 206
207 // Set stdin, stdout to binary mode 207 // Set stdin, stdout to binary mode
208 QPDF_DLL 208 QPDF_DLL
@@ -431,16 +431,16 @@ namespace QUtil @@ -431,16 +431,16 @@ namespace QUtil
431 // These routines help the tokenizer recognize certain character classes without using ctype, 431 // These routines help the tokenizer recognize certain character classes without using ctype,
432 // which we avoid because of locale considerations. 432 // which we avoid because of locale considerations.
433 QPDF_DLL 433 QPDF_DLL
434 - inline bool is_hex_digit(char); 434 + bool is_hex_digit(char);
435 435
436 QPDF_DLL 436 QPDF_DLL
437 - inline bool is_space(char); 437 + bool is_space(char);
438 438
439 QPDF_DLL 439 QPDF_DLL
440 - inline bool is_digit(char); 440 + bool is_digit(char);
441 441
442 QPDF_DLL 442 QPDF_DLL
443 - inline bool is_number(char const*); 443 + bool is_number(char const*);
444 444
445 // This method parses the numeric range syntax used by the qpdf command-line tool. May throw 445 // This method parses the numeric range syntax used by the qpdf command-line tool. May throw
446 // std::runtime_error. A numeric range is as comma-separated list of groups. A group may be a 446 // std::runtime_error. A numeric range is as comma-separated list of groups. A group may be a
@@ -489,65 +489,4 @@ namespace QUtil @@ -489,65 +489,4 @@ namespace QUtil
489 size_t get_max_memory_usage(); 489 size_t get_max_memory_usage();
490 }; // namespace QUtil 490 }; // namespace QUtil
491 491
492 -inline bool  
493 -QUtil::is_hex_digit(char ch)  
494 -{  
495 - return hex_decode_char(ch) < '\20';  
496 -}  
497 -  
498 -inline bool  
499 -QUtil::is_space(char ch)  
500 -{  
501 - return ch == ' ' || ch == '\n' || ch == '\r' || ch == '\t' || ch == '\f' || ch == '\v';  
502 -}  
503 -  
504 -inline bool  
505 -QUtil::is_digit(char ch)  
506 -{  
507 - return ((ch >= '0') && (ch <= '9'));  
508 -}  
509 -  
510 -inline bool  
511 -QUtil::is_number(char const* p)  
512 -{  
513 - // ^[\+\-]?(\.\d*|\d+(\.\d*)?)$  
514 - if (!*p) {  
515 - return false;  
516 - }  
517 - if ((*p == '-') || (*p == '+')) {  
518 - ++p;  
519 - }  
520 - bool found_dot = false;  
521 - bool found_digit = false;  
522 - for (; *p; ++p) {  
523 - if (*p == '.') {  
524 - if (found_dot) {  
525 - // only one dot  
526 - return false;  
527 - }  
528 - found_dot = true;  
529 - } else if (QUtil::is_digit(*p)) {  
530 - found_digit = true;  
531 - } else {  
532 - return false;  
533 - }  
534 - }  
535 - return found_digit;  
536 -}  
537 -  
538 -inline std::string  
539 -QUtil::hex_encode_char(char c)  
540 -{  
541 - static auto constexpr hexchars = "0123456789abcdef";  
542 - return {'#', hexchars[static_cast<unsigned char>(c) >> 4], hexchars[c & 0x0f]};  
543 -}  
544 -  
545 -inline constexpr char  
546 -QUtil::hex_decode_char(char digit) noexcept  
547 -{  
548 - return digit <= '9' && digit >= '0'  
549 - ? char(digit - '0')  
550 - : (digit >= 'a' ? char(digit - 'a' + 10) : (digit >= 'A' ? char(digit - 'A' + 10) : '\20'));  
551 -}  
552 -  
553 #endif // QUTIL_HH 492 #endif // QUTIL_HH
libqpdf/JSON.cc
@@ -8,9 +8,13 @@ @@ -8,9 +8,13 @@
8 #include <qpdf/Pl_String.hh> 8 #include <qpdf/Pl_String.hh>
9 #include <qpdf/QTC.hh> 9 #include <qpdf/QTC.hh>
10 #include <qpdf/QUtil.hh> 10 #include <qpdf/QUtil.hh>
  11 +#include <qpdf/Util.hh>
  12 +
11 #include <cstring> 13 #include <cstring>
12 #include <stdexcept> 14 #include <stdexcept>
13 15
  16 +using namespace qpdf;
  17 +
14 JSON::Members::Members(std::unique_ptr<JSON_value> value) : 18 JSON::Members::Members(std::unique_ptr<JSON_value> value) :
15 value(std::move(value)) 19 value(std::move(value))
16 { 20 {
@@ -761,7 +765,7 @@ JSONParser::tokenError() @@ -761,7 +765,7 @@ JSONParser::tokenError()
761 QTC::TC("libtests", "JSON parse unexpected sign"); 765 QTC::TC("libtests", "JSON parse unexpected sign");
762 throw std::runtime_error( 766 throw std::runtime_error(
763 "JSON: offset " + std::to_string(offset) + ": numeric literal: unexpected sign"); 767 "JSON: offset " + std::to_string(offset) + ": numeric literal: unexpected sign");
764 - } else if (QUtil::is_space(*p) || strchr("{}[]:,", *p)) { 768 + } else if (util::is_space(*p) || strchr("{}[]:,", *p)) {
765 QTC::TC("libtests", "JSON parse incomplete number"); 769 QTC::TC("libtests", "JSON parse incomplete number");
766 throw std::runtime_error( 770 throw std::runtime_error(
767 "JSON: offset " + std::to_string(offset) + ": numeric literal: incomplete number"); 771 "JSON: offset " + std::to_string(offset) + ": numeric literal: incomplete number");
@@ -1078,7 +1082,7 @@ JSONParser::getToken() @@ -1078,7 +1082,7 @@ JSONParser::getToken()
1078 1082
1079 case ls_u4: 1083 case ls_u4:
1080 using ui = unsigned int; 1084 using ui = unsigned int;
1081 - if (ui val = ui(QUtil::hex_decode_char(*p)); val < 16) { 1085 + if (ui val = ui(util::hex_decode_char(*p)); val < 16) {
1082 u_value = 16 * u_value + val; 1086 u_value = 16 * u_value + val;
1083 } else { 1087 } else {
1084 tokenError(); 1088 tokenError();
libqpdf/Pl_Base64.cc
@@ -2,9 +2,13 @@ @@ -2,9 +2,13 @@
2 2
3 #include <qpdf/QIntC.hh> 3 #include <qpdf/QIntC.hh>
4 #include <qpdf/QUtil.hh> 4 #include <qpdf/QUtil.hh>
  5 +#include <qpdf/Util.hh>
  6 +
5 #include <cstring> 7 #include <cstring>
6 #include <stdexcept> 8 #include <stdexcept>
7 9
  10 +using namespace qpdf;
  11 +
8 static char 12 static char
9 to_c(unsigned int ch) 13 to_c(unsigned int ch)
10 { 14 {
@@ -50,7 +54,7 @@ Pl_Base64::decode(unsigned char const* data, size_t len) @@ -50,7 +54,7 @@ Pl_Base64::decode(unsigned char const* data, size_t len)
50 { 54 {
51 unsigned char const* p = data; 55 unsigned char const* p = data;
52 while (len > 0) { 56 while (len > 0) {
53 - if (!QUtil::is_space(to_c(*p))) { 57 + if (!util::is_space(to_c(*p))) {
54 this->buf[this->pos++] = *p; 58 this->buf[this->pos++] = *p;
55 if (this->pos == 4) { 59 if (this->pos == 4) {
56 flush(); 60 flush();
libqpdf/QPDF.cc
@@ -22,6 +22,9 @@ @@ -22,6 +22,9 @@
22 #include <qpdf/QPDFParser.hh> 22 #include <qpdf/QPDFParser.hh>
23 #include <qpdf/QTC.hh> 23 #include <qpdf/QTC.hh>
24 #include <qpdf/QUtil.hh> 24 #include <qpdf/QUtil.hh>
  25 +#include <qpdf/Util.hh>
  26 +
  27 +using namespace qpdf;
25 28
26 // This must be a fixed value. This API returns a const reference to it, and the C API relies on its 29 // This must be a fixed value. This API returns a const reference to it, and the C API relies on its
27 // being static as well. 30 // being static as well.
@@ -368,14 +371,14 @@ QPDF::numWarnings() const @@ -368,14 +371,14 @@ QPDF::numWarnings() const
368 bool 371 bool
369 QPDF::validatePDFVersion(char const*& p, std::string& version) 372 QPDF::validatePDFVersion(char const*& p, std::string& version)
370 { 373 {
371 - bool valid = QUtil::is_digit(*p); 374 + bool valid = util::is_digit(*p);
372 if (valid) { 375 if (valid) {
373 - while (QUtil::is_digit(*p)) { 376 + while (util::is_digit(*p)) {
374 version.append(1, *p++); 377 version.append(1, *p++);
375 } 378 }
376 - if ((*p == '.') && QUtil::is_digit(*(p + 1))) { 379 + if ((*p == '.') && util::is_digit(*(p + 1))) {
377 version.append(1, *p++); 380 version.append(1, *p++);
378 - while (QUtil::is_digit(*p)) { 381 + while (util::is_digit(*p)) {
379 version.append(1, *p++); 382 version.append(1, *p++);
380 } 383 }
381 } else { 384 } else {
@@ -709,7 +712,7 @@ QPDF::read_xref(qpdf_offset_t xref_offset) @@ -709,7 +712,7 @@ QPDF::read_xref(qpdf_offset_t xref_offset)
709 while (!done) { 712 while (!done) {
710 char ch; 713 char ch;
711 if (1 == m->file->read(&ch, 1)) { 714 if (1 == m->file->read(&ch, 1)) {
712 - if (QUtil::is_space(ch)) { 715 + if (util::is_space(ch)) {
713 skipped_space = true; 716 skipped_space = true;
714 } else { 717 } else {
715 m->file->unreadCh(ch); 718 m->file->unreadCh(ch);
@@ -724,7 +727,7 @@ QPDF::read_xref(qpdf_offset_t xref_offset) @@ -724,7 +727,7 @@ QPDF::read_xref(qpdf_offset_t xref_offset)
724 m->file->read(buf, sizeof(buf) - 1); 727 m->file->read(buf, sizeof(buf) - 1);
725 // The PDF spec says xref must be followed by a line terminator, but files exist in the wild 728 // The PDF spec says xref must be followed by a line terminator, but files exist in the wild
726 // where it is terminated by arbitrary whitespace. 729 // where it is terminated by arbitrary whitespace.
727 - if ((strncmp(buf, "xref", 4) == 0) && QUtil::is_space(buf[4])) { 730 + if ((strncmp(buf, "xref", 4) == 0) && util::is_space(buf[4])) {
728 if (skipped_space) { 731 if (skipped_space) {
729 QTC::TC("qpdf", "QPDF xref skipped space"); 732 QTC::TC("qpdf", "QPDF xref skipped space");
730 warn(damagedPDF("", 0, "extraneous whitespace seen before xref")); 733 warn(damagedPDF("", 0, "extraneous whitespace seen before xref"));
@@ -737,8 +740,8 @@ QPDF::read_xref(qpdf_offset_t xref_offset) @@ -737,8 +740,8 @@ QPDF::read_xref(qpdf_offset_t xref_offset)
737 : (buf[4] == ' ') ? 2 740 : (buf[4] == ' ') ? 2
738 : 9999)); 741 : 9999));
739 int skip = 4; 742 int skip = 4;
740 - // buf is null-terminated, and QUtil::is_space('\0') is false, so this won't overrun.  
741 - while (QUtil::is_space(buf[skip])) { 743 + // buf is null-terminated, and util::is_space('\0') is false, so this won't overrun.
  744 + while (util::is_space(buf[skip])) {
742 ++skip; 745 ++skip;
743 } 746 }
744 xref_offset = read_xrefTable(xref_offset + skip); 747 xref_offset = read_xrefTable(xref_offset + skip);
@@ -795,37 +798,37 @@ QPDF::parse_xrefFirst(std::string const&amp; line, int&amp; obj, int&amp; num, int&amp; bytes) @@ -795,37 +798,37 @@ QPDF::parse_xrefFirst(std::string const&amp; line, int&amp; obj, int&amp; num, int&amp; bytes)
795 char const* start = line.c_str(); 798 char const* start = line.c_str();
796 799
797 // Skip zero or more spaces 800 // Skip zero or more spaces
798 - while (QUtil::is_space(*p)) { 801 + while (util::is_space(*p)) {
799 ++p; 802 ++p;
800 } 803 }
801 // Require digit 804 // Require digit
802 - if (!QUtil::is_digit(*p)) { 805 + if (!util::is_digit(*p)) {
803 return false; 806 return false;
804 } 807 }
805 // Gather digits 808 // Gather digits
806 std::string obj_str; 809 std::string obj_str;
807 - while (QUtil::is_digit(*p)) { 810 + while (util::is_digit(*p)) {
808 obj_str.append(1, *p++); 811 obj_str.append(1, *p++);
809 } 812 }
810 // Require space 813 // Require space
811 - if (!QUtil::is_space(*p)) { 814 + if (!util::is_space(*p)) {
812 return false; 815 return false;
813 } 816 }
814 // Skip spaces 817 // Skip spaces
815 - while (QUtil::is_space(*p)) { 818 + while (util::is_space(*p)) {
816 ++p; 819 ++p;
817 } 820 }
818 // Require digit 821 // Require digit
819 - if (!QUtil::is_digit(*p)) { 822 + if (!util::is_digit(*p)) {
820 return false; 823 return false;
821 } 824 }
822 // Gather digits 825 // Gather digits
823 std::string num_str; 826 std::string num_str;
824 - while (QUtil::is_digit(*p)) { 827 + while (util::is_digit(*p)) {
825 num_str.append(1, *p++); 828 num_str.append(1, *p++);
826 } 829 }
827 // Skip any space including line terminators 830 // Skip any space including line terminators
828 - while (QUtil::is_space(*p)) { 831 + while (util::is_space(*p)) {
829 ++p; 832 ++p;
830 } 833 }
831 bytes = toI(p - start); 834 bytes = toI(p - start);
@@ -847,51 +850,51 @@ QPDF::read_bad_xrefEntry(qpdf_offset_t&amp; f1, int&amp; f2, char&amp; type) @@ -847,51 +850,51 @@ QPDF::read_bad_xrefEntry(qpdf_offset_t&amp; f1, int&amp; f2, char&amp; type)
847 850
848 // Skip zero or more spaces. There aren't supposed to be any. 851 // Skip zero or more spaces. There aren't supposed to be any.
849 bool invalid = false; 852 bool invalid = false;
850 - while (QUtil::is_space(*p)) { 853 + while (util::is_space(*p)) {
851 ++p; 854 ++p;
852 QTC::TC("qpdf", "QPDF ignore first space in xref entry"); 855 QTC::TC("qpdf", "QPDF ignore first space in xref entry");
853 invalid = true; 856 invalid = true;
854 } 857 }
855 // Require digit 858 // Require digit
856 - if (!QUtil::is_digit(*p)) { 859 + if (!util::is_digit(*p)) {
857 return false; 860 return false;
858 } 861 }
859 // Gather digits 862 // Gather digits
860 std::string f1_str; 863 std::string f1_str;
861 - while (QUtil::is_digit(*p)) { 864 + while (util::is_digit(*p)) {
862 f1_str.append(1, *p++); 865 f1_str.append(1, *p++);
863 } 866 }
864 // Require space 867 // Require space
865 - if (!QUtil::is_space(*p)) { 868 + if (!util::is_space(*p)) {
866 return false; 869 return false;
867 } 870 }
868 - if (QUtil::is_space(*(p + 1))) { 871 + if (util::is_space(*(p + 1))) {
869 QTC::TC("qpdf", "QPDF ignore first extra space in xref entry"); 872 QTC::TC("qpdf", "QPDF ignore first extra space in xref entry");
870 invalid = true; 873 invalid = true;
871 } 874 }
872 // Skip spaces 875 // Skip spaces
873 - while (QUtil::is_space(*p)) { 876 + while (util::is_space(*p)) {
874 ++p; 877 ++p;
875 } 878 }
876 // Require digit 879 // Require digit
877 - if (!QUtil::is_digit(*p)) { 880 + if (!util::is_digit(*p)) {
878 return false; 881 return false;
879 } 882 }
880 // Gather digits 883 // Gather digits
881 std::string f2_str; 884 std::string f2_str;
882 - while (QUtil::is_digit(*p)) { 885 + while (util::is_digit(*p)) {
883 f2_str.append(1, *p++); 886 f2_str.append(1, *p++);
884 } 887 }
885 // Require space 888 // Require space
886 - if (!QUtil::is_space(*p)) { 889 + if (!util::is_space(*p)) {
887 return false; 890 return false;
888 } 891 }
889 - if (QUtil::is_space(*(p + 1))) { 892 + if (util::is_space(*(p + 1))) {
890 QTC::TC("qpdf", "QPDF ignore second extra space in xref entry"); 893 QTC::TC("qpdf", "QPDF ignore second extra space in xref entry");
891 invalid = true; 894 invalid = true;
892 } 895 }
893 // Skip spaces 896 // Skip spaces
894 - while (QUtil::is_space(*p)) { 897 + while (util::is_space(*p)) {
895 ++p; 898 ++p;
896 } 899 }
897 if ((*p == 'f') || (*p == 'n')) { 900 if ((*p == 'f') || (*p == 'n')) {
@@ -938,12 +941,12 @@ QPDF::read_xrefEntry(qpdf_offset_t&amp; f1, int&amp; f2, char&amp; type) @@ -938,12 +941,12 @@ QPDF::read_xrefEntry(qpdf_offset_t&amp; f1, int&amp; f2, char&amp; type)
938 ++f1_len; 941 ++f1_len;
939 ++p; 942 ++p;
940 } 943 }
941 - while (QUtil::is_digit(*p) && f1_len++ < 10) { 944 + while (util::is_digit(*p) && f1_len++ < 10) {
942 f1 *= 10; 945 f1 *= 10;
943 f1 += *p++ - '0'; 946 f1 += *p++ - '0';
944 } 947 }
945 // Require space 948 // Require space
946 - if (!QUtil::is_space(*p++)) { 949 + if (!util::is_space(*p++)) {
947 // Entry doesn't start with space or digit. 950 // Entry doesn't start with space or digit.
948 // C++20: [[unlikely]] 951 // C++20: [[unlikely]]
949 return false; 952 return false;
@@ -953,11 +956,11 @@ QPDF::read_xrefEntry(qpdf_offset_t&amp; f1, int&amp; f2, char&amp; type) @@ -953,11 +956,11 @@ QPDF::read_xrefEntry(qpdf_offset_t&amp; f1, int&amp; f2, char&amp; type)
953 ++f2_len; 956 ++f2_len;
954 ++p; 957 ++p;
955 } 958 }
956 - while (QUtil::is_digit(*p) && f2_len++ < 5) { 959 + while (util::is_digit(*p) && f2_len++ < 5) {
957 f2 *= 10; 960 f2 *= 10;
958 f2 += static_cast<int>(*p++ - '0'); 961 f2 += static_cast<int>(*p++ - '0');
959 } 962 }
960 - if (QUtil::is_space(*p++) && (*p == 'f' || *p == 'n')) { 963 + if (util::is_space(*p++) && (*p == 'f' || *p == 'n')) {
961 // C++20: [[likely]] 964 // C++20: [[likely]]
962 type = *p; 965 type = *p;
963 // No test for valid line[19]. 966 // No test for valid line[19].
@@ -1602,7 +1605,7 @@ QPDF::validateStreamLineEnd(QPDFObjectHandle&amp; object, QPDFObjGen og, qpdf_offset @@ -1602,7 +1605,7 @@ QPDF::validateStreamLineEnd(QPDFObjectHandle&amp; object, QPDFObjGen og, qpdf_offset
1602 } 1605 }
1603 return; 1606 return;
1604 } 1607 }
1605 - if (!QUtil::is_space(ch)) { 1608 + if (!util::is_space(ch)) {
1606 QTC::TC("qpdf", "QPDF stream without newline"); 1609 QTC::TC("qpdf", "QPDF stream without newline");
1607 m->file->unreadCh(ch); 1610 m->file->unreadCh(ch);
1608 warn(damagedPDF( 1611 warn(damagedPDF(
libqpdf/QPDFArgParser.cc
@@ -5,10 +5,13 @@ @@ -5,10 +5,13 @@
5 #include <qpdf/QPDFUsage.hh> 5 #include <qpdf/QPDFUsage.hh>
6 #include <qpdf/QTC.hh> 6 #include <qpdf/QTC.hh>
7 #include <qpdf/QUtil.hh> 7 #include <qpdf/QUtil.hh>
  8 +#include <qpdf/Util.hh>
  9 +
8 #include <cstdlib> 10 #include <cstdlib>
9 #include <cstring> 11 #include <cstring>
10 #include <iostream> 12 #include <iostream>
11 13
  14 +using namespace qpdf;
12 using namespace std::literals; 15 using namespace std::literals;
13 16
14 QPDFArgParser::Members::Members(int argc, char const* const argv[], char const* progname_env) : 17 QPDFArgParser::Members::Members(int argc, char const* const argv[], char const* progname_env) :
@@ -285,7 +288,7 @@ QPDFArgParser::handleBashArguments() @@ -285,7 +288,7 @@ QPDFArgParser::handleBashArguments()
285 bool append = false; 288 bool append = false;
286 switch (state) { 289 switch (state) {
287 case st_top: 290 case st_top:
288 - if (QUtil::is_space(ch)) { 291 + if (util::is_space(ch)) {
289 if (!arg.empty()) { 292 if (!arg.empty()) {
290 m->bash_argv.push_back(QUtil::make_shared_cstr(arg)); 293 m->bash_argv.push_back(QUtil::make_shared_cstr(arg));
291 arg.clear(); 294 arg.clear();
libqpdf/QPDFJob.cc
@@ -29,9 +29,12 @@ @@ -29,9 +29,12 @@
29 #include <qpdf/QPDFWriter.hh> 29 #include <qpdf/QPDFWriter.hh>
30 #include <qpdf/QTC.hh> 30 #include <qpdf/QTC.hh>
31 #include <qpdf/QUtil.hh> 31 #include <qpdf/QUtil.hh>
  32 +#include <qpdf/Util.hh>
32 33
33 #include <qpdf/auto_job_schema.hh> // JOB_SCHEMA_DATA 34 #include <qpdf/auto_job_schema.hh> // JOB_SCHEMA_DATA
34 35
  36 +using namespace qpdf;
  37 +
35 namespace 38 namespace
36 { 39 {
37 class ImageOptimizer: public QPDFObjectHandle::StreamDataProvider 40 class ImageOptimizer: public QPDFObjectHandle::StreamDataProvider
@@ -388,7 +391,7 @@ QPDFJob::parseRotationParameter(std::string const&amp; parameter) @@ -388,7 +391,7 @@ QPDFJob::parseRotationParameter(std::string const&amp; parameter)
388 if ((first == '+') || (first == '-')) { 391 if ((first == '+') || (first == '-')) {
389 relative = ((first == '+') ? 1 : -1); 392 relative = ((first == '+') ? 1 : -1);
390 angle_str = angle_str.substr(1); 393 angle_str = angle_str.substr(1);
391 - } else if (!QUtil::is_digit(angle_str.at(0))) { 394 + } else if (!util::is_digit(angle_str.at(0))) {
392 angle_str = ""; 395 angle_str = "";
393 } 396 }
394 } 397 }
libqpdf/QPDFObjectHandle.cc
@@ -15,6 +15,7 @@ @@ -15,6 +15,7 @@
15 #include <qpdf/QIntC.hh> 15 #include <qpdf/QIntC.hh>
16 #include <qpdf/QTC.hh> 16 #include <qpdf/QTC.hh>
17 #include <qpdf/QUtil.hh> 17 #include <qpdf/QUtil.hh>
  18 +#include <qpdf/Util.hh>
18 19
19 #include <algorithm> 20 #include <algorithm>
20 #include <array> 21 #include <array>
@@ -279,7 +280,7 @@ Name::normalize(std::string const&amp; name) @@ -279,7 +280,7 @@ Name::normalize(std::string const&amp; name)
279 } else if ( 280 } else if (
280 ch < 33 || ch == '#' || ch == '/' || ch == '(' || ch == ')' || ch == '{' || ch == '}' || 281 ch < 33 || ch == '#' || ch == '/' || ch == '(' || ch == ')' || ch == '{' || ch == '}' ||
281 ch == '<' || ch == '>' || ch == '[' || ch == ']' || ch == '%' || ch > 126) { 282 ch == '<' || ch == '>' || ch == '[' || ch == ']' || ch == '%' || ch > 126) {
282 - result += QUtil::hex_encode_char(ch); 283 + result += util::hex_encode_char(ch);
283 } else { 284 } else {
284 result += ch; 285 result += ch;
285 } 286 }
libqpdf/QPDFTokenizer.cc
@@ -8,11 +8,14 @@ @@ -8,11 +8,14 @@
8 #include <qpdf/QPDFObjectHandle.hh> 8 #include <qpdf/QPDFObjectHandle.hh>
9 #include <qpdf/QTC.hh> 9 #include <qpdf/QTC.hh>
10 #include <qpdf/QUtil.hh> 10 #include <qpdf/QUtil.hh>
  11 +#include <qpdf/Util.hh>
11 12
12 #include <cstdlib> 13 #include <cstdlib>
13 #include <cstring> 14 #include <cstring>
14 #include <stdexcept> 15 #include <stdexcept>
15 16
  17 +using namespace qpdf;
  18 +
16 static inline bool 19 static inline bool
17 is_delimiter(char ch) 20 is_delimiter(char ch)
18 { 21 {
@@ -123,7 +126,7 @@ QPDFTokenizer::includeIgnorable() @@ -123,7 +126,7 @@ QPDFTokenizer::includeIgnorable()
123 bool 126 bool
124 QPDFTokenizer::isSpace(char ch) 127 QPDFTokenizer::isSpace(char ch)
125 { 128 {
126 - return ((ch == '\0') || QUtil::is_space(ch)); 129 + return (ch == '\0' || util::is_space(ch));
127 } 130 }
128 131
129 bool 132 bool
@@ -440,7 +443,7 @@ QPDFTokenizer::inNameHex1(char ch) @@ -440,7 +443,7 @@ QPDFTokenizer::inNameHex1(char ch)
440 { 443 {
441 this->hex_char = ch; 444 this->hex_char = ch;
442 445
443 - if (char hval = QUtil::hex_decode_char(ch); hval < '0') { 446 + if (char hval = util::hex_decode_char(ch); hval < '0') {
444 this->char_code = int(hval) << 4; 447 this->char_code = int(hval) << 4;
445 this->state = st_name_hex2; 448 this->state = st_name_hex2;
446 } else { 449 } else {
@@ -456,7 +459,7 @@ QPDFTokenizer::inNameHex1(char ch) @@ -456,7 +459,7 @@ QPDFTokenizer::inNameHex1(char ch)
456 void 459 void
457 QPDFTokenizer::inNameHex2(char ch) 460 QPDFTokenizer::inNameHex2(char ch)
458 { 461 {
459 - if (char hval = QUtil::hex_decode_char(ch); hval < '0') { 462 + if (char hval = util::hex_decode_char(ch); hval < '0') {
460 this->char_code |= int(hval); 463 this->char_code |= int(hval);
461 } else { 464 } else {
462 QTC::TC("qpdf", "QPDFTokenizer bad name 2"); 465 QTC::TC("qpdf", "QPDFTokenizer bad name 2");
@@ -483,7 +486,7 @@ QPDFTokenizer::inNameHex2(char ch) @@ -483,7 +486,7 @@ QPDFTokenizer::inNameHex2(char ch)
483 void 486 void
484 QPDFTokenizer::inSign(char ch) 487 QPDFTokenizer::inSign(char ch)
485 { 488 {
486 - if (QUtil::is_digit(ch)) { 489 + if (util::is_digit(ch)) {
487 this->state = st_number; 490 this->state = st_number;
488 } else if (ch == '.') { 491 } else if (ch == '.') {
489 this->state = st_decimal; 492 this->state = st_decimal;
@@ -496,7 +499,7 @@ QPDFTokenizer::inSign(char ch) @@ -496,7 +499,7 @@ QPDFTokenizer::inSign(char ch)
496 void 499 void
497 QPDFTokenizer::inDecimal(char ch) 500 QPDFTokenizer::inDecimal(char ch)
498 { 501 {
499 - if (QUtil::is_digit(ch)) { 502 + if (util::is_digit(ch)) {
500 this->state = st_real; 503 this->state = st_real;
501 } else { 504 } else {
502 this->state = st_literal; 505 this->state = st_literal;
@@ -507,7 +510,7 @@ QPDFTokenizer::inDecimal(char ch) @@ -507,7 +510,7 @@ QPDFTokenizer::inDecimal(char ch)
507 void 510 void
508 QPDFTokenizer::inNumber(char ch) 511 QPDFTokenizer::inNumber(char ch)
509 { 512 {
510 - if (QUtil::is_digit(ch)) { 513 + if (util::is_digit(ch)) {
511 } else if (ch == '.') { 514 } else if (ch == '.') {
512 this->state = st_real; 515 this->state = st_real;
513 } else if (isDelimiter(ch)) { 516 } else if (isDelimiter(ch)) {
@@ -523,7 +526,7 @@ QPDFTokenizer::inNumber(char ch) @@ -523,7 +526,7 @@ QPDFTokenizer::inNumber(char ch)
523 void 526 void
524 QPDFTokenizer::inReal(char ch) 527 QPDFTokenizer::inReal(char ch)
525 { 528 {
526 - if (QUtil::is_digit(ch)) { 529 + if (util::is_digit(ch)) {
527 } else if (isDelimiter(ch)) { 530 } else if (isDelimiter(ch)) {
528 this->type = tt_real; 531 this->type = tt_real;
529 this->state = st_token_ready; 532 this->state = st_token_ready;
@@ -645,7 +648,7 @@ QPDFTokenizer::inLiteral(char ch) @@ -645,7 +648,7 @@ QPDFTokenizer::inLiteral(char ch)
645 void 648 void
646 QPDFTokenizer::inHexstring(char ch) 649 QPDFTokenizer::inHexstring(char ch)
647 { 650 {
648 - if (char hval = QUtil::hex_decode_char(ch); hval < '0') { 651 + if (char hval = util::hex_decode_char(ch); hval < '0') {
649 this->char_code = int(hval) << 4; 652 this->char_code = int(hval) << 4;
650 this->state = st_in_hexstring_2nd; 653 this->state = st_in_hexstring_2nd;
651 654
@@ -667,7 +670,7 @@ QPDFTokenizer::inHexstring(char ch) @@ -667,7 +670,7 @@ QPDFTokenizer::inHexstring(char ch)
667 void 670 void
668 QPDFTokenizer::inHexstring2nd(char ch) 671 QPDFTokenizer::inHexstring2nd(char ch)
669 { 672 {
670 - if (char hval = QUtil::hex_decode_char(ch); hval < '0') { 673 + if (char hval = util::hex_decode_char(ch); hval < '0') {
671 this->val += char(this->char_code) | hval; 674 this->val += char(this->char_code) | hval;
672 this->state = st_in_hexstring; 675 this->state = st_in_hexstring;
673 676
libqpdf/QPDF_json.cc
@@ -9,9 +9,13 @@ @@ -9,9 +9,13 @@
9 #include <qpdf/QPDFObject_private.hh> 9 #include <qpdf/QPDFObject_private.hh>
10 #include <qpdf/QTC.hh> 10 #include <qpdf/QTC.hh>
11 #include <qpdf/QUtil.hh> 11 #include <qpdf/QUtil.hh>
  12 +#include <qpdf/Util.hh>
  13 +
12 #include <algorithm> 14 #include <algorithm>
13 #include <cstring> 15 #include <cstring>
14 16
  17 +using namespace qpdf;
  18 +
15 // This chart shows an example of the state transitions that would occur in parsing a minimal file. 19 // This chart shows an example of the state transitions that would occur in parsing a minimal file.
16 20
17 // | 21 // |
@@ -67,10 +71,10 @@ is_indirect_object(std::string const&amp; v, int&amp; obj, int&amp; gen) @@ -67,10 +71,10 @@ is_indirect_object(std::string const&amp; v, int&amp; obj, int&amp; gen)
67 char const* p = v.c_str(); 71 char const* p = v.c_str();
68 std::string o_str; 72 std::string o_str;
69 std::string g_str; 73 std::string g_str;
70 - if (!QUtil::is_digit(*p)) { 74 + if (!util::is_digit(*p)) {
71 return false; 75 return false;
72 } 76 }
73 - while (QUtil::is_digit(*p)) { 77 + while (util::is_digit(*p)) {
74 o_str.append(1, *p++); 78 o_str.append(1, *p++);
75 } 79 }
76 if (*p != ' ') { 80 if (*p != ' ') {
@@ -79,10 +83,10 @@ is_indirect_object(std::string const&amp; v, int&amp; obj, int&amp; gen) @@ -79,10 +83,10 @@ is_indirect_object(std::string const&amp; v, int&amp; obj, int&amp; gen)
79 while (*p == ' ') { 83 while (*p == ' ') {
80 ++p; 84 ++p;
81 } 85 }
82 - if (!QUtil::is_digit(*p)) { 86 + if (!util::is_digit(*p)) {
83 return false; 87 return false;
84 } 88 }
85 - while (QUtil::is_digit(*p)) { 89 + while (util::is_digit(*p)) {
86 g_str.append(1, *p++); 90 g_str.append(1, *p++);
87 } 91 }
88 if (*p != ' ') { 92 if (*p != ' ') {
@@ -128,7 +132,7 @@ is_binary_string(std::string const&amp; v, std::string&amp; str) @@ -128,7 +132,7 @@ is_binary_string(std::string const&amp; v, std::string&amp; str)
128 str = v.substr(2); 132 str = v.substr(2);
129 int count = 0; 133 int count = 0;
130 for (char c: str) { 134 for (char c: str) {
131 - if (!QUtil::is_hex_digit(c)) { 135 + if (!util::is_hex_digit(c)) {
132 return false; 136 return false;
133 } 137 }
134 ++count; 138 ++count;
libqpdf/QPDF_linearization.cc
@@ -12,11 +12,14 @@ @@ -12,11 +12,14 @@
12 #include <qpdf/QPDFWriter_private.hh> 12 #include <qpdf/QPDFWriter_private.hh>
13 #include <qpdf/QTC.hh> 13 #include <qpdf/QTC.hh>
14 #include <qpdf/QUtil.hh> 14 #include <qpdf/QUtil.hh>
  15 +#include <qpdf/Util.hh>
15 16
16 #include <algorithm> 17 #include <algorithm>
17 #include <cmath> 18 #include <cmath>
18 #include <cstring> 19 #include <cstring>
19 20
  21 +using namespace qpdf;
  22 +
20 template <class T, class int_type> 23 template <class T, class int_type>
21 static void 24 static void
22 load_vector_int( 25 load_vector_int(
@@ -105,7 +108,7 @@ QPDF::isLinearized() @@ -105,7 +108,7 @@ QPDF::isLinearized()
105 char* p = buf; 108 char* p = buf;
106 while (lindict_obj == -1) { 109 while (lindict_obj == -1) {
107 // Find a digit or end of buffer 110 // Find a digit or end of buffer
108 - while (((p - buf) < tbuf_size) && (!QUtil::is_digit(*p))) { 111 + while (((p - buf) < tbuf_size) && (!util::is_digit(*p))) {
109 ++p; 112 ++p;
110 } 113 }
111 if (p - buf == tbuf_size) { 114 if (p - buf == tbuf_size) {
@@ -114,7 +117,7 @@ QPDF::isLinearized() @@ -114,7 +117,7 @@ QPDF::isLinearized()
114 // Seek to the digit. Then skip over digits for a potential 117 // Seek to the digit. Then skip over digits for a potential
115 // next iteration. 118 // next iteration.
116 m->file->seek(p - buf, SEEK_SET); 119 m->file->seek(p - buf, SEEK_SET);
117 - while (((p - buf) < tbuf_size) && QUtil::is_digit(*p)) { 120 + while (((p - buf) < tbuf_size) && util::is_digit(*p)) {
118 ++p; 121 ++p;
119 } 122 }
120 123
libqpdf/QUtil.cc
@@ -8,6 +8,7 @@ @@ -8,6 +8,7 @@
8 #include <qpdf/QIntC.hh> 8 #include <qpdf/QIntC.hh>
9 #include <qpdf/QPDFSystemError.hh> 9 #include <qpdf/QPDFSystemError.hh>
10 #include <qpdf/QTC.hh> 10 #include <qpdf/QTC.hh>
  11 +#include <qpdf/Util.hh>
11 12
12 #include <cerrno> 13 #include <cerrno>
13 #include <cstdlib> 14 #include <cstdlib>
@@ -37,6 +38,8 @@ @@ -37,6 +38,8 @@
37 # include <malloc.h> 38 # include <malloc.h>
38 #endif 39 #endif
39 40
  41 +using namespace qpdf;
  42 +
40 // First element is 24 43 // First element is 24
41 static unsigned short pdf_doc_low_to_unicode[] = { 44 static unsigned short pdf_doc_low_to_unicode[] = {
42 0x02d8, // 0x18 BREVE 45 0x02d8, // 0x18 BREVE
@@ -396,7 +399,7 @@ unsigned long long @@ -396,7 +399,7 @@ unsigned long long
396 QUtil::string_to_ull(char const* str) 399 QUtil::string_to_ull(char const* str)
397 { 400 {
398 char const* p = str; 401 char const* p = str;
399 - while (*p && is_space(*p)) { 402 + while (*p && util::is_space(*p)) {
400 ++p; 403 ++p;
401 } 404 }
402 if (*p == '-') { 405 if (*p == '-') {
@@ -739,7 +742,7 @@ QUtil::hex_decode(std::string const&amp; input) @@ -739,7 +742,7 @@ QUtil::hex_decode(std::string const&amp; input)
739 bool first = true; 742 bool first = true;
740 char decoded; 743 char decoded;
741 for (auto ch: input) { 744 for (auto ch: input) {
742 - ch = hex_decode_char(ch); 745 + ch = util::hex_decode_char(ch);
743 if (ch < '\20') { 746 if (ch < '\20') {
744 if (first) { 747 if (first) {
745 decoded = static_cast<char>(ch << 4); 748 decoded = static_cast<char>(ch << 4);
@@ -2002,3 +2005,63 @@ QUtil::get_max_memory_usage() @@ -2002,3 +2005,63 @@ QUtil::get_max_memory_usage()
2002 return 0; 2005 return 0;
2003 #endif 2006 #endif
2004 } 2007 }
  2008 +
  2009 +char
  2010 +QUtil::hex_decode_char(char digit)
  2011 +{
  2012 + return util::hex_decode_char(digit);
  2013 +}
  2014 +
  2015 +std::string
  2016 +QUtil::hex_encode_char(char c)
  2017 +{
  2018 + return util::hex_encode_char(c);
  2019 +}
  2020 +
  2021 +bool
  2022 +QUtil::is_number(char const* p)
  2023 +{
  2024 + // No longer used by qpdf.
  2025 +
  2026 + // ^[\+\-]?(\.\d*|\d+(\.\d*)?)$
  2027 + if (!*p) {
  2028 + return false;
  2029 + }
  2030 + if ((*p == '-') || (*p == '+')) {
  2031 + ++p;
  2032 + }
  2033 + bool found_dot = false;
  2034 + bool found_digit = false;
  2035 + for (; *p; ++p) {
  2036 + if (*p == '.') {
  2037 + if (found_dot) {
  2038 + // only one dot
  2039 + return false;
  2040 + }
  2041 + found_dot = true;
  2042 + } else if (util::is_digit(*p)) {
  2043 + found_digit = true;
  2044 + } else {
  2045 + return false;
  2046 + }
  2047 + }
  2048 + return found_digit;
  2049 +}
  2050 +
  2051 +bool
  2052 +QUtil::is_space(char c)
  2053 +{
  2054 + return util::is_space(c);
  2055 +}
  2056 +
  2057 +bool
  2058 +QUtil::is_digit(char c)
  2059 +{
  2060 + return util::is_digit(c);
  2061 +}
  2062 +
  2063 +bool
  2064 +QUtil::is_hex_digit(char c)
  2065 +{
  2066 + return util::is_hex_digit(c);
  2067 +}
libqpdf/qpdf/Util.hh 0 → 100644
  1 +#ifndef UTIL_HH
  2 +#define UTIL_HH
  3 +
  4 +#include <string>
  5 +
  6 +namespace qpdf::util
  7 +{
  8 + // This is a collection of useful utility functions for qpdf internal use. They include inline
  9 + // functions, some of which are exposed as regular functions in QUtil. Implementations are in
  10 + // QUtil.cc.
  11 +
  12 + inline constexpr char
  13 + hex_decode_char(char digit)
  14 + {
  15 + return digit <= '9' && digit >= '0'
  16 + ? char(digit - '0')
  17 + : (digit >= 'a' ? char(digit - 'a' + 10)
  18 + : (digit >= 'A' ? char(digit - 'A' + 10) : '\20'));
  19 + }
  20 +
  21 + inline constexpr bool
  22 + is_hex_digit(char ch)
  23 + {
  24 + return hex_decode_char(ch) < '\20';
  25 + }
  26 +
  27 + inline constexpr bool
  28 + is_space(char ch)
  29 + {
  30 + return ch == ' ' || ch == '\n' || ch == '\r' || ch == '\t' || ch == '\f' || ch == '\v';
  31 + }
  32 +
  33 + inline bool
  34 + is_digit(char ch)
  35 + {
  36 + return (ch >= '0' && ch <= '9');
  37 + }
  38 +
  39 + // Returns lower-case hex-encoded version of the char including a leading "#".
  40 + inline std::string
  41 + hex_encode_char(char c)
  42 + {
  43 + static auto constexpr hexchars = "0123456789abcdef";
  44 + return {'#', hexchars[static_cast<unsigned char>(c) >> 4], hexchars[c & 0x0f]};
  45 + }
  46 +
  47 +} // namespace qpdf::util
  48 +
  49 +#endif // UTIL_HH