You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
173 lines
4.9 KiB
173 lines
4.9 KiB
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
|
|
file Copyright.txt or https://cmake.org/licensing for details. */
|
|
|
|
#include "cmProcessOutput.h"
|
|
|
|
#if defined(_WIN32)
|
|
# include <cm/memory>
|
|
|
|
# include <windows.h>
|
|
|
|
unsigned int cmProcessOutput::defaultCodepage =
|
|
KWSYS_ENCODING_DEFAULT_CODEPAGE;
|
|
#endif
|
|
|
|
cm::optional<cmProcessOutput::Encoding> cmProcessOutput::FindEncoding(
|
|
std::string const& name)
|
|
{
|
|
cm::optional<Encoding> encoding;
|
|
if ((name == "UTF8") || (name == "UTF-8")) {
|
|
encoding = UTF8;
|
|
} else if (name == "NONE") {
|
|
encoding = None;
|
|
} else if (name == "ANSI") {
|
|
encoding = ANSI;
|
|
} else if (name == "AUTO") {
|
|
encoding = Auto;
|
|
} else if (name == "OEM") {
|
|
encoding = OEM;
|
|
}
|
|
return encoding;
|
|
}
|
|
|
|
cmProcessOutput::cmProcessOutput(Encoding encoding, unsigned int maxSize)
|
|
{
|
|
#if defined(_WIN32)
|
|
codepage = 0;
|
|
bufferSize = maxSize;
|
|
if (encoding == None) {
|
|
codepage = defaultCodepage;
|
|
} else if (encoding == Auto) {
|
|
codepage = GetConsoleCP();
|
|
} else if (encoding == UTF8) {
|
|
codepage = CP_UTF8;
|
|
} else if (encoding == OEM) {
|
|
codepage = GetOEMCP();
|
|
}
|
|
if (!codepage || encoding == ANSI) {
|
|
codepage = GetACP();
|
|
}
|
|
#else
|
|
static_cast<void>(encoding);
|
|
static_cast<void>(maxSize);
|
|
#endif
|
|
}
|
|
|
|
bool cmProcessOutput::DecodeText(std::string raw, std::string& decoded,
|
|
size_t id)
|
|
{
|
|
#if !defined(_WIN32)
|
|
static_cast<void>(id);
|
|
decoded.swap(raw);
|
|
return true;
|
|
#else
|
|
bool success = true;
|
|
decoded = raw;
|
|
if (id > 0) {
|
|
if (rawparts.size() < id) {
|
|
rawparts.reserve(id);
|
|
while (rawparts.size() < id)
|
|
rawparts.push_back(std::string());
|
|
}
|
|
raw = rawparts[id - 1] + raw;
|
|
rawparts[id - 1].clear();
|
|
decoded = raw;
|
|
}
|
|
if (raw.size() > 0 && codepage != defaultCodepage) {
|
|
success = false;
|
|
CPINFOEXW cpinfo;
|
|
if (id > 0 && bufferSize > 0 && raw.size() == bufferSize &&
|
|
GetCPInfoExW(codepage, 0, &cpinfo) == 1 && cpinfo.MaxCharSize > 1) {
|
|
if (cpinfo.MaxCharSize == 2 && cpinfo.LeadByte[0] != 0) {
|
|
LPSTR prevChar =
|
|
CharPrevExA(codepage, raw.c_str(), raw.c_str() + raw.size(), 0);
|
|
bool isLeadByte =
|
|
(*(prevChar + 1) == 0) && IsDBCSLeadByteEx(codepage, *prevChar);
|
|
if (isLeadByte) {
|
|
rawparts[id - 1] += *(raw.end() - 1);
|
|
raw.resize(raw.size() - 1);
|
|
}
|
|
success = DoDecodeText(raw, decoded, nullptr);
|
|
} else {
|
|
bool restoreDecoded = false;
|
|
std::string firstDecoded = decoded;
|
|
wchar_t lastChar = 0;
|
|
for (UINT i = 0; i < cpinfo.MaxCharSize; i++) {
|
|
success = DoDecodeText(raw, decoded, &lastChar);
|
|
if (success && lastChar != 0) {
|
|
if (i == 0) {
|
|
firstDecoded = decoded;
|
|
}
|
|
if (lastChar == cpinfo.UnicodeDefaultChar) {
|
|
restoreDecoded = true;
|
|
rawparts[id - 1] = *(raw.end() - 1) + rawparts[id - 1];
|
|
raw.resize(raw.size() - 1);
|
|
} else {
|
|
restoreDecoded = false;
|
|
break;
|
|
}
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
if (restoreDecoded) {
|
|
decoded = firstDecoded;
|
|
rawparts[id - 1].clear();
|
|
}
|
|
}
|
|
} else {
|
|
success = DoDecodeText(raw, decoded, nullptr);
|
|
}
|
|
}
|
|
return success;
|
|
#endif
|
|
}
|
|
|
|
bool cmProcessOutput::DecodeText(const char* data, size_t length,
|
|
std::string& decoded, size_t id)
|
|
{
|
|
return this->DecodeText(std::string(data, length), decoded, id);
|
|
}
|
|
|
|
bool cmProcessOutput::DecodeText(std::vector<char> raw,
|
|
std::vector<char>& decoded, size_t id)
|
|
{
|
|
std::string str;
|
|
const bool success =
|
|
this->DecodeText(std::string(raw.begin(), raw.end()), str, id);
|
|
decoded.assign(str.begin(), str.end());
|
|
return success;
|
|
}
|
|
|
|
#if defined(_WIN32)
|
|
bool cmProcessOutput::DoDecodeText(std::string raw, std::string& decoded,
|
|
wchar_t* lastChar)
|
|
{
|
|
bool success = false;
|
|
const int wlength =
|
|
MultiByteToWideChar(codepage, 0, raw.c_str(), int(raw.size()), nullptr, 0);
|
|
auto wdata = cm::make_unique<wchar_t[]>(wlength);
|
|
int r = MultiByteToWideChar(codepage, 0, raw.c_str(), int(raw.size()),
|
|
wdata.get(), wlength);
|
|
if (r > 0) {
|
|
if (lastChar) {
|
|
*lastChar = 0;
|
|
if ((wlength >= 2 && wdata[wlength - 2] != wdata[wlength - 1]) ||
|
|
wlength >= 1) {
|
|
*lastChar = wdata[wlength - 1];
|
|
}
|
|
}
|
|
int length = WideCharToMultiByte(defaultCodepage, 0, wdata.get(), wlength,
|
|
nullptr, 0, nullptr, nullptr);
|
|
auto data = cm::make_unique<char[]>(length);
|
|
r = WideCharToMultiByte(defaultCodepage, 0, wdata.get(), wlength,
|
|
data.get(), length, nullptr, nullptr);
|
|
if (r > 0) {
|
|
decoded = std::string(data.get(), length);
|
|
success = true;
|
|
}
|
|
}
|
|
return success;
|
|
}
|
|
#endif
|