Commit a44b5a34a07b9f2905d419d5571fd53832c1f6c0
1 parent
ab4061f1
Pull wmain -> main code from qpdf.cc into QUtil.cc
Showing
6 changed files
with
67 additions
and
30 deletions
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
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 | ... | ... |