/* 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 # include unsigned int cmProcessOutput::defaultCodepage = KWSYS_ENCODING_DEFAULT_CODEPAGE; #endif cm::optional cmProcessOutput::FindEncoding( std::string const& name) { cm::optional 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(encoding); static_cast(maxSize); #endif } bool cmProcessOutput::DecodeText(std::string raw, std::string& decoded, size_t id) { #if !defined(_WIN32) static_cast(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 raw, std::vector& 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(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(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