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 7 2020-01-13 Jay Berkenbilt <ejb@ql.org>
2 8  
3 9 * QUtil::read_lines_from_file: add new versions that use FILE*,
... ...
include/qpdf/QUtil.hh
... ... @@ -362,6 +362,13 @@ namespace QUtil
362 362 // command-line tool. May throw std::runtime_error.
363 363 QPDF_DLL
364 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 374 #endif // QUTIL_HH
... ...
libqpdf/QUtil.cc
... ... @@ -23,6 +23,7 @@
23 23 #include <stdlib.h>
24 24 #include <string.h>
25 25 #include <fcntl.h>
  26 +#include <memory>
26 27 #ifdef _WIN32
27 28 #include <windows.h>
28 29 #include <direct.h>
... ... @@ -2361,3 +2362,38 @@ QUtil::possible_repaired_encodings(std::string supplied)
2361 2362 }
2362 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 105 create file
106 106 rename over existing
107 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 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 557 int main(int argc, char* argv[])
547 558 {
548 559 try
... ... @@ -573,6 +584,8 @@ int main(int argc, char* argv[])
573 584 hex_encode_decode_test();
574 585 std::cout << "---- rename/delete" << std::endl;
575 586 rename_delete_test();
  587 + std::cout << "---- wmain" << std::endl;
  588 + wmain_test();
576 589 }
577 590 catch (std::exception& e)
578 591 {
... ...
qpdf/qpdf.cc
... ... @@ -5304,36 +5304,7 @@ int realmain(int argc, char* argv[])
5304 5304 extern "C"
5305 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 5310 #else
... ...