summaryrefslogtreecommitdiffstats
path: root/Source/cmProcessOutput.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'Source/cmProcessOutput.cxx')
-rw-r--r--Source/cmProcessOutput.cxx155
1 files changed, 155 insertions, 0 deletions
diff --git a/Source/cmProcessOutput.cxx b/Source/cmProcessOutput.cxx
new file mode 100644
index 0000000..1440223
--- /dev/null
+++ b/Source/cmProcessOutput.cxx
@@ -0,0 +1,155 @@
+/* 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 <windows.h>
+unsigned int cmProcessOutput::defaultCodepage =
+ KWSYS_ENCODING_DEFAULT_CODEPAGE;
+#endif
+
+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
+}
+
+cmProcessOutput::~cmProcessOutput()
+{
+}
+
+bool cmProcessOutput::DecodeText(std::string raw, std::string& decoded,
+ size_t id)
+{
+ bool success = true;
+ decoded = raw;
+#if defined(_WIN32)
+ 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, NULL);
+ } 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, NULL);
+ }
+ }
+#else
+ static_cast<void>(id);
+#endif
+ return success;
+}
+
+bool cmProcessOutput::DecodeText(const char* data, size_t length,
+ std::string& decoded, size_t id)
+{
+ return 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 =
+ 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()), NULL, 0);
+ wchar_t* wdata = new wchar_t[wlength];
+ int r = MultiByteToWideChar(codepage, 0, raw.c_str(), int(raw.size()), wdata,
+ 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, wlength, NULL,
+ 0, NULL, NULL);
+ char* data = new char[length];
+ r = WideCharToMultiByte(defaultCodepage, 0, wdata, wlength, data, length,
+ NULL, NULL);
+ if (r > 0) {
+ decoded = std::string(data, length);
+ success = true;
+ }
+ delete[] data;
+ }
+ delete[] wdata;
+ return success;
+}
+#endif