| /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying | |
| file LICENSE.rst 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(char const* 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; | |
| bool const 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; | |
| int const 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 |