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