Commit a44b5a34a07b9f2905d419d5571fd53832c1f6c0

Authored by Jay Berkenbilt
1 parent ab4061f1

Pull wmain -> main code from qpdf.cc into QUtil.cc

ChangeLog
  1 +2020-01-14 Jay Berkenbilt <ejb@ql.org>
  2 +
  3 + * Add QUtil::call_main_from_wmain, a helper function that can be
  4 + called in the body of wmain to convert UTF-16 arguments to UTF-8
  5 + arguments and then call another main function.
  6 +
1 2020-01-13 Jay Berkenbilt <ejb@ql.org> 7 2020-01-13 Jay Berkenbilt <ejb@ql.org>
2 8
3 * QUtil::read_lines_from_file: add new versions that use FILE*, 9 * QUtil::read_lines_from_file: add new versions that use FILE*,
include/qpdf/QUtil.hh
@@ -362,6 +362,13 @@ namespace QUtil @@ -362,6 +362,13 @@ namespace QUtil
362 // command-line tool. May throw std::runtime_error. 362 // command-line tool. May throw std::runtime_error.
363 QPDF_DLL 363 QPDF_DLL
364 std::vector<int> parse_numrange(char const* range, int max); 364 std::vector<int> parse_numrange(char const* range, int max);
  365 +
  366 + // Take an argv array consisting of wchar_t, as when wmain is
  367 + // invoked, convert all UTF-16 encoded strings to UTF-8, and call
  368 + // another main.
  369 + QPDF_DLL
  370 + int call_main_from_wmain(int argc, wchar_t* argv[],
  371 + std::function<int(int, char*[])> realmain);
365 }; 372 };
366 373
367 #endif // QUTIL_HH 374 #endif // QUTIL_HH
libqpdf/QUtil.cc
@@ -23,6 +23,7 @@ @@ -23,6 +23,7 @@
23 #include <stdlib.h> 23 #include <stdlib.h>
24 #include <string.h> 24 #include <string.h>
25 #include <fcntl.h> 25 #include <fcntl.h>
  26 +#include <memory>
26 #ifdef _WIN32 27 #ifdef _WIN32
27 #include <windows.h> 28 #include <windows.h>
28 #include <direct.h> 29 #include <direct.h>
@@ -2361,3 +2362,38 @@ QUtil::possible_repaired_encodings(std::string supplied) @@ -2361,3 +2362,38 @@ QUtil::possible_repaired_encodings(std::string supplied)
2361 } 2362 }
2362 return t; 2363 return t;
2363 } 2364 }
  2365 +
  2366 +int
  2367 +QUtil::call_main_from_wmain(int argc, wchar_t* argv[], std::function<int(int, char*[])> realmain)
  2368 +{
  2369 + // argv contains UTF-16-encoded strings with a 16-bit wchar_t.
  2370 + // Convert this to UTF-8-encoded strings for compatibility with
  2371 + // other systems. That way the rest of qpdf.cc can just act like
  2372 + // arguments are UTF-8.
  2373 +
  2374 + std::vector<std::shared_ptr<char>> utf8_argv;
  2375 + for (int i = 0; i < argc; ++i)
  2376 + {
  2377 + std::string utf16;
  2378 + for (size_t j = 0; j < wcslen(argv[i]); ++j)
  2379 + {
  2380 + unsigned short codepoint = static_cast<unsigned short>(argv[i][j]);
  2381 + utf16.append(1, static_cast<char>(
  2382 + QIntC::to_uchar(codepoint >> 8)));
  2383 + utf16.append(1, static_cast<char>(
  2384 + QIntC::to_uchar(codepoint & 0xff)));
  2385 + }
  2386 + std::string utf8 = QUtil::utf16_to_utf8(utf16);
  2387 + utf8_argv.push_back(std::shared_ptr<char>(QUtil::copy_string(utf8.c_str()), std::default_delete<char[]>()));
  2388 + }
  2389 + auto utf8_argv_sp =
  2390 + std::shared_ptr<char*>(new char*[1+utf8_argv.size()], std::default_delete<char*[]>());
  2391 + char** new_argv = utf8_argv_sp.get();
  2392 + for (size_t i = 0; i < utf8_argv.size(); ++i)
  2393 + {
  2394 + new_argv[i] = utf8_argv.at(i).get();
  2395 + }
  2396 + argc = QIntC::to_int(utf8_argv.size());
  2397 + new_argv[argc] = 0;
  2398 + return realmain(argc, new_argv);
  2399 +}
libtests/qtest/qutil/qutil.out
@@ -105,3 +105,7 @@ rename file @@ -105,3 +105,7 @@ rename file
105 create file 105 create file
106 rename over existing 106 rename over existing
107 delete file 107 delete file
  108 +---- wmain
  109 +ascii
  110 +10 ÷ 2 = 5
  111 +qwww÷π
libtests/qutil.cc
@@ -543,6 +543,17 @@ void rename_delete_test() @@ -543,6 +543,17 @@ void rename_delete_test()
543 assert_no_file("old\xcf\x80.~tmp"); 543 assert_no_file("old\xcf\x80.~tmp");
544 } 544 }
545 545
  546 +void wmain_test()
  547 +{
  548 + auto realmain = [](int argc, char* argv[]) {
  549 + for (int i = 0; i < argc; ++i) { std::cout << argv[i] << std::endl; } return 0; };
  550 + wchar_t* argv[3];
  551 + argv[0] = const_cast<wchar_t*>(L"ascii");
  552 + argv[1] = const_cast<wchar_t*>(L"10 \xf7 2 = 5");
  553 + argv[2] = const_cast<wchar_t*>(L"qwww\xf7\x03c0");
  554 + QUtil::call_main_from_wmain(3, argv, realmain);
  555 +}
  556 +
546 int main(int argc, char* argv[]) 557 int main(int argc, char* argv[])
547 { 558 {
548 try 559 try
@@ -573,6 +584,8 @@ int main(int argc, char* argv[]) @@ -573,6 +584,8 @@ int main(int argc, char* argv[])
573 hex_encode_decode_test(); 584 hex_encode_decode_test();
574 std::cout << "---- rename/delete" << std::endl; 585 std::cout << "---- rename/delete" << std::endl;
575 rename_delete_test(); 586 rename_delete_test();
  587 + std::cout << "---- wmain" << std::endl;
  588 + wmain_test();
576 } 589 }
577 catch (std::exception& e) 590 catch (std::exception& e)
578 { 591 {
qpdf/qpdf.cc
@@ -5304,36 +5304,7 @@ int realmain(int argc, char* argv[]) @@ -5304,36 +5304,7 @@ int realmain(int argc, char* argv[])
5304 extern "C" 5304 extern "C"
5305 int wmain(int argc, wchar_t* argv[]) 5305 int wmain(int argc, wchar_t* argv[])
5306 { 5306 {
5307 - // If wmain is supported, argv contains UTF-16-encoded strings  
5308 - // with a 16-bit wchar_t. Convert this to UTF-8-encoded strings  
5309 - // for compatibility with other systems. That way the rest of  
5310 - // qpdf.cc can just act like arguments are UTF-8.  
5311 - std::vector<PointerHolder<char> > utf8_argv;  
5312 - for (int i = 0; i < argc; ++i)  
5313 - {  
5314 - std::string utf16;  
5315 - for (size_t j = 0; j < wcslen(argv[i]); ++j)  
5316 - {  
5317 - unsigned short codepoint = static_cast<unsigned short>(argv[i][j]);  
5318 - utf16.append(1, static_cast<char>(  
5319 - QIntC::to_uchar(codepoint >> 8)));  
5320 - utf16.append(1, static_cast<char>(  
5321 - QIntC::to_uchar(codepoint & 0xff)));  
5322 - }  
5323 - std::string utf8 = QUtil::utf16_to_utf8(utf16);  
5324 - utf8_argv.push_back(  
5325 - PointerHolder<char>(true, QUtil::copy_string(utf8.c_str())));  
5326 - }  
5327 - PointerHolder<char*> utf8_argv_ph =  
5328 - PointerHolder<char*>(true, new char*[1+utf8_argv.size()]);  
5329 - char** new_argv = utf8_argv_ph.getPointer();  
5330 - for (size_t i = 0; i < utf8_argv.size(); ++i)  
5331 - {  
5332 - new_argv[i] = utf8_argv.at(i).getPointer();  
5333 - }  
5334 - argc = QIntC::to_int(utf8_argv.size());  
5335 - new_argv[argc] = 0;  
5336 - return realmain(argc, new_argv); 5307 + return QUtil::call_main_from_wmain(argc, argv, realmain);
5337 } 5308 }
5338 5309
5339 #else 5310 #else