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 | 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
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 |