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

This commit is contained in:
Jay Berkenbilt 2020-01-14 11:38:48 -05:00
parent ab4061f1ee
commit a44b5a34a0
6 changed files with 67 additions and 30 deletions

View File

@ -1,3 +1,9 @@
2020-01-14 Jay Berkenbilt <ejb@ql.org>
* Add QUtil::call_main_from_wmain, a helper function that can be
called in the body of wmain to convert UTF-16 arguments to UTF-8
arguments and then call another main function.
2020-01-13 Jay Berkenbilt <ejb@ql.org>
* QUtil::read_lines_from_file: add new versions that use FILE*,

View File

@ -362,6 +362,13 @@ namespace QUtil
// command-line tool. May throw std::runtime_error.
QPDF_DLL
std::vector<int> parse_numrange(char const* range, int max);
// Take an argv array consisting of wchar_t, as when wmain is
// invoked, convert all UTF-16 encoded strings to UTF-8, and call
// another main.
QPDF_DLL
int call_main_from_wmain(int argc, wchar_t* argv[],
std::function<int(int, char*[])> realmain);
};
#endif // QUTIL_HH

View File

@ -23,6 +23,7 @@
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <memory>
#ifdef _WIN32
#include <windows.h>
#include <direct.h>
@ -2361,3 +2362,38 @@ QUtil::possible_repaired_encodings(std::string supplied)
}
return t;
}
int
QUtil::call_main_from_wmain(int argc, wchar_t* argv[], std::function<int(int, char*[])> realmain)
{
// argv contains UTF-16-encoded strings with a 16-bit wchar_t.
// Convert this to UTF-8-encoded strings for compatibility with
// other systems. That way the rest of qpdf.cc can just act like
// arguments are UTF-8.
std::vector<std::shared_ptr<char>> utf8_argv;
for (int i = 0; i < argc; ++i)
{
std::string utf16;
for (size_t j = 0; j < wcslen(argv[i]); ++j)
{
unsigned short codepoint = static_cast<unsigned short>(argv[i][j]);
utf16.append(1, static_cast<char>(
QIntC::to_uchar(codepoint >> 8)));
utf16.append(1, static_cast<char>(
QIntC::to_uchar(codepoint & 0xff)));
}
std::string utf8 = QUtil::utf16_to_utf8(utf16);
utf8_argv.push_back(std::shared_ptr<char>(QUtil::copy_string(utf8.c_str()), std::default_delete<char[]>()));
}
auto utf8_argv_sp =
std::shared_ptr<char*>(new char*[1+utf8_argv.size()], std::default_delete<char*[]>());
char** new_argv = utf8_argv_sp.get();
for (size_t i = 0; i < utf8_argv.size(); ++i)
{
new_argv[i] = utf8_argv.at(i).get();
}
argc = QIntC::to_int(utf8_argv.size());
new_argv[argc] = 0;
return realmain(argc, new_argv);
}

View File

@ -105,3 +105,7 @@ rename file
create file
rename over existing
delete file
---- wmain
ascii
10 ÷ 2 = 5
qwww÷π

View File

@ -543,6 +543,17 @@ void rename_delete_test()
assert_no_file("old\xcf\x80.~tmp");
}
void wmain_test()
{
auto realmain = [](int argc, char* argv[]) {
for (int i = 0; i < argc; ++i) { std::cout << argv[i] << std::endl; } return 0; };
wchar_t* argv[3];
argv[0] = const_cast<wchar_t*>(L"ascii");
argv[1] = const_cast<wchar_t*>(L"10 \xf7 2 = 5");
argv[2] = const_cast<wchar_t*>(L"qwww\xf7\x03c0");
QUtil::call_main_from_wmain(3, argv, realmain);
}
int main(int argc, char* argv[])
{
try
@ -573,6 +584,8 @@ int main(int argc, char* argv[])
hex_encode_decode_test();
std::cout << "---- rename/delete" << std::endl;
rename_delete_test();
std::cout << "---- wmain" << std::endl;
wmain_test();
}
catch (std::exception& e)
{

View File

@ -5304,36 +5304,7 @@ int realmain(int argc, char* argv[])
extern "C"
int wmain(int argc, wchar_t* argv[])
{
// If wmain is supported, argv contains UTF-16-encoded strings
// with a 16-bit wchar_t. Convert this to UTF-8-encoded strings
// for compatibility with other systems. That way the rest of
// qpdf.cc can just act like arguments are UTF-8.
std::vector<PointerHolder<char> > utf8_argv;
for (int i = 0; i < argc; ++i)
{
std::string utf16;
for (size_t j = 0; j < wcslen(argv[i]); ++j)
{
unsigned short codepoint = static_cast<unsigned short>(argv[i][j]);
utf16.append(1, static_cast<char>(
QIntC::to_uchar(codepoint >> 8)));
utf16.append(1, static_cast<char>(
QIntC::to_uchar(codepoint & 0xff)));
}
std::string utf8 = QUtil::utf16_to_utf8(utf16);
utf8_argv.push_back(
PointerHolder<char>(true, QUtil::copy_string(utf8.c_str())));
}
PointerHolder<char*> utf8_argv_ph =
PointerHolder<char*>(true, new char*[1+utf8_argv.size()]);
char** new_argv = utf8_argv_ph.getPointer();
for (size_t i = 0; i < utf8_argv.size(); ++i)
{
new_argv[i] = utf8_argv.at(i).getPointer();
}
argc = QIntC::to_int(utf8_argv.size());
new_argv[argc] = 0;
return realmain(argc, new_argv);
return QUtil::call_main_from_wmain(argc, argv, realmain);
}
#else