Commit 76c4f78b5cfd786b90069f7256252229444fdecd

Authored by Jay Berkenbilt
1 parent 67f9d0b7

Add QUtil::make_shared_cstr

Replace most of the calls to QUtil::copy_string with this instead.
ChangeLog
1 2022-01-22 Jay Berkenbilt <ejb@ql.org> 1 2022-01-22 Jay Berkenbilt <ejb@ql.org>
2 2
  3 + * Add QUtil::make_shared_cstr to return a std::shared_ptr<char>
  4 + instead of a char* like QUtil::copy_string
  5 +
3 * JSON: for (qpdf-specific, not official) "schema" checking, add 6 * JSON: for (qpdf-specific, not official) "schema" checking, add
4 the ability to treat missing fields as optional. Also ensure that 7 the ability to treat missing fields as optional. Also ensure that
5 values in the schema are dictionary, array, or string. 8 values in the schema are dictionary, array, or string.
include/qpdf/QUtil.hh
@@ -30,6 +30,7 @@ @@ -30,6 +30,7 @@
30 #include <vector> 30 #include <vector>
31 #include <stdexcept> 31 #include <stdexcept>
32 #include <functional> 32 #include <functional>
  33 +#include <memory>
33 #include <stdio.h> 34 #include <stdio.h>
34 #include <time.h> 35 #include <time.h>
35 36
@@ -151,9 +152,15 @@ namespace QUtil @@ -151,9 +152,15 @@ namespace QUtil
151 QPDF_DLL 152 QPDF_DLL
152 std::string path_basename(std::string const& filename); 153 std::string path_basename(std::string const& filename);
153 154
  155 + // Returns a dynamically allocated copy of a string that the
  156 + // caller has to delete with delete[].
154 QPDF_DLL 157 QPDF_DLL
155 char* copy_string(std::string const&); 158 char* copy_string(std::string const&);
156 159
  160 + // Returns a shared_ptr<char> with the correct deleter.
  161 + QPDF_DLL
  162 + std::shared_ptr<char> make_shared_cstr(std::string const&);
  163 +
157 // Returns lower-case hex-encoded version of the string, treating 164 // Returns lower-case hex-encoded version of the string, treating
158 // each character in the input string as unsigned. The output 165 // each character in the input string as unsigned. The output
159 // string will be twice as long as the input string. 166 // string will be twice as long as the input string.
libqpdf/QPDFWriter.cc
@@ -1915,9 +1915,8 @@ QPDFWriter::unparseObject(QPDFObjectHandle object, int level, @@ -1915,9 +1915,8 @@ QPDFWriter::unparseObject(QPDFObjectHandle object, int level,
1915 } 1915 }
1916 else 1916 else
1917 { 1917 {
1918 - PointerHolder<char> tmp_ph =  
1919 - PointerHolder<char>(true, QUtil::copy_string(val));  
1920 - char* tmp = tmp_ph.getPointer(); 1918 + auto tmp_ph = QUtil::make_shared_cstr(val);
  1919 + char* tmp = tmp_ph.get();
1921 size_t vlen = val.length(); 1920 size_t vlen = val.length();
1922 RC4 rc4(QUtil::unsigned_char_pointer(this->m->cur_data_key), 1921 RC4 rc4(QUtil::unsigned_char_pointer(this->m->cur_data_key),
1923 QIntC::to_int(this->m->cur_data_key.length())); 1922 QIntC::to_int(this->m->cur_data_key.length()));
libqpdf/QPDF_encryption.cc
@@ -1211,10 +1211,10 @@ QPDF::decryptString(std::string&amp; str, int objid, int generation) @@ -1211,10 +1211,10 @@ QPDF::decryptString(std::string&amp; str, int objid, int generation)
1211 size_t vlen = str.length(); 1211 size_t vlen = str.length();
1212 // Using PointerHolder guarantees that tmp will 1212 // Using PointerHolder guarantees that tmp will
1213 // be freed even if rc4.process throws an exception. 1213 // be freed even if rc4.process throws an exception.
1214 - PointerHolder<char> tmp(true, QUtil::copy_string(str)); 1214 + auto tmp = QUtil::make_shared_cstr(str);
1215 RC4 rc4(QUtil::unsigned_char_pointer(key), toI(key.length())); 1215 RC4 rc4(QUtil::unsigned_char_pointer(key), toI(key.length()));
1216 - rc4.process(QUtil::unsigned_char_pointer(tmp.getPointer()), vlen);  
1217 - str = std::string(tmp.getPointer(), vlen); 1216 + rc4.process(QUtil::unsigned_char_pointer(tmp.get()), vlen);
  1217 + str = std::string(tmp.get(), vlen);
1218 } 1218 }
1219 } 1219 }
1220 catch (QPDFExc&) 1220 catch (QPDFExc&)
libqpdf/QUtil.cc
@@ -731,6 +731,18 @@ QUtil::copy_string(std::string const&amp; str) @@ -731,6 +731,18 @@ QUtil::copy_string(std::string const&amp; str)
731 return result; 731 return result;
732 } 732 }
733 733
  734 +std::shared_ptr<char>
  735 +QUtil::make_shared_cstr(std::string const& str)
  736 +{
  737 + auto result = std::shared_ptr<char>(
  738 + new char[str.length() + 1],
  739 + std::default_delete<char[]>());
  740 + // Use memcpy in case string contains nulls
  741 + result.get()[str.length()] = '\0';
  742 + memcpy(result.get(), str.c_str(), str.length());
  743 + return result;
  744 +}
  745 +
734 std::string 746 std::string
735 QUtil::hex_encode(std::string const& input) 747 QUtil::hex_encode(std::string const& input)
736 { 748 {
@@ -2625,7 +2637,7 @@ QUtil::call_main_from_wmain(int argc, wchar_t* argv[], @@ -2625,7 +2637,7 @@ QUtil::call_main_from_wmain(int argc, wchar_t* argv[],
2625 QIntC::to_uchar(codepoint & 0xff))); 2637 QIntC::to_uchar(codepoint & 0xff)));
2626 } 2638 }
2627 std::string utf8 = QUtil::utf16_to_utf8(utf16); 2639 std::string utf8 = QUtil::utf16_to_utf8(utf16);
2628 - utf8_argv.push_back(std::shared_ptr<char>(QUtil::copy_string(utf8.c_str()), std::default_delete<char[]>())); 2640 + utf8_argv.push_back(QUtil::make_shared_cstr(utf8));
2629 } 2641 }
2630 auto utf8_argv_sp = 2642 auto utf8_argv_sp =
2631 std::shared_ptr<char*>(new char*[1+utf8_argv.size()], std::default_delete<char*[]>()); 2643 std::shared_ptr<char*>(new char*[1+utf8_argv.size()], std::default_delete<char*[]>());
libtests/qtest/qutil/qutil.out
@@ -22,6 +22,7 @@ @@ -22,6 +22,7 @@
22 one 22 one
23 7 23 7
24 compare okay 24 compare okay
  25 +compare okay
25 -2147483648 to int: PASSED 26 -2147483648 to int: PASSED
26 2147483647 to int: PASSED 27 2147483647 to int: PASSED
27 2147483648 to int threw (integer out of range converting 2147483648 from a 8-byte signed type to a 4-byte signed type): PASSED 28 2147483648 to int threw (integer out of range converting 2147483648 from a 8-byte signed type to a 4-byte signed type): PASSED
libtests/qutil.cc
@@ -150,6 +150,16 @@ void string_conversion_test() @@ -150,6 +150,16 @@ void string_conversion_test()
150 std::cout << "compare failed" << std::endl; 150 std::cout << "compare failed" << std::endl;
151 } 151 }
152 delete [] tmp; 152 delete [] tmp;
  153 + // Also test with make_shared_cstr
  154 + auto tmp2 = QUtil::make_shared_cstr(embedded_null);
  155 + if (memcmp(tmp2.get(), embedded_null.c_str(), 7) == 0)
  156 + {
  157 + std::cout << "compare okay" << std::endl;
  158 + }
  159 + else
  160 + {
  161 + std::cout << "compare failed" << std::endl;
  162 + }
153 163
154 std::string int_max_str = QUtil::int_to_string(INT_MAX); 164 std::string int_max_str = QUtil::int_to_string(INT_MAX);
155 std::string int_min_str = QUtil::int_to_string(INT_MIN); 165 std::string int_min_str = QUtil::int_to_string(INT_MIN);
@@ -407,8 +417,8 @@ void transcoding_test() @@ -407,8 +417,8 @@ void transcoding_test()
407 417
408 void print_whoami(char const* str) 418 void print_whoami(char const* str)
409 { 419 {
410 - PointerHolder<char> dup(true, QUtil::copy_string(str));  
411 - std::cout << QUtil::getWhoami(dup.getPointer()) << std::endl; 420 + auto dup = QUtil::make_shared_cstr(str);
  421 + std::cout << QUtil::getWhoami(dup.get()) << std::endl;
412 } 422 }
413 423
414 void get_whoami_test() 424 void get_whoami_test()