1 /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
2 file Copyright.txt or https://cmake.org/licensing for details. */
3
4 #include "cmProcessOutput.h"
5
6 #if defined(_WIN32)
7 # include <cm/memory>
8
9 # include <windows.h>
10
11 unsigned int cmProcessOutput::defaultCodepage =
12 KWSYS_ENCODING_DEFAULT_CODEPAGE;
13 #endif
14
FindEncoding(std::string const & name)15 cmProcessOutput::Encoding cmProcessOutput::FindEncoding(
16 std::string const& name)
17 {
18 Encoding encoding = Auto;
19 if ((name == "UTF8") || (name == "UTF-8")) {
20 encoding = UTF8;
21 } else if (name == "NONE") {
22 encoding = None;
23 } else if (name == "ANSI") {
24 encoding = ANSI;
25 } else if (name == "OEM") {
26 encoding = OEM;
27 }
28 return encoding;
29 }
30
cmProcessOutput(Encoding encoding,unsigned int maxSize)31 cmProcessOutput::cmProcessOutput(Encoding encoding, unsigned int maxSize)
32 {
33 #if defined(_WIN32)
34 codepage = 0;
35 bufferSize = maxSize;
36 if (encoding == None) {
37 codepage = defaultCodepage;
38 } else if (encoding == Auto) {
39 codepage = GetConsoleCP();
40 } else if (encoding == UTF8) {
41 codepage = CP_UTF8;
42 } else if (encoding == OEM) {
43 codepage = GetOEMCP();
44 }
45 if (!codepage || encoding == ANSI) {
46 codepage = GetACP();
47 }
48 #else
49 static_cast<void>(encoding);
50 static_cast<void>(maxSize);
51 #endif
52 }
53
DecodeText(std::string raw,std::string & decoded,size_t id)54 bool cmProcessOutput::DecodeText(std::string raw, std::string& decoded,
55 size_t id)
56 {
57 #if !defined(_WIN32)
58 static_cast<void>(id);
59 decoded.swap(raw);
60 return true;
61 #else
62 bool success = true;
63 decoded = raw;
64 if (id > 0) {
65 if (rawparts.size() < id) {
66 rawparts.reserve(id);
67 while (rawparts.size() < id)
68 rawparts.push_back(std::string());
69 }
70 raw = rawparts[id - 1] + raw;
71 rawparts[id - 1].clear();
72 decoded = raw;
73 }
74 if (raw.size() > 0 && codepage != defaultCodepage) {
75 success = false;
76 CPINFOEXW cpinfo;
77 if (id > 0 && bufferSize > 0 && raw.size() == bufferSize &&
78 GetCPInfoExW(codepage, 0, &cpinfo) == 1 && cpinfo.MaxCharSize > 1) {
79 if (cpinfo.MaxCharSize == 2 && cpinfo.LeadByte[0] != 0) {
80 LPSTR prevChar =
81 CharPrevExA(codepage, raw.c_str(), raw.c_str() + raw.size(), 0);
82 bool isLeadByte =
83 (*(prevChar + 1) == 0) && IsDBCSLeadByteEx(codepage, *prevChar);
84 if (isLeadByte) {
85 rawparts[id - 1] += *(raw.end() - 1);
86 raw.resize(raw.size() - 1);
87 }
88 success = DoDecodeText(raw, decoded, NULL);
89 } else {
90 bool restoreDecoded = false;
91 std::string firstDecoded = decoded;
92 wchar_t lastChar = 0;
93 for (UINT i = 0; i < cpinfo.MaxCharSize; i++) {
94 success = DoDecodeText(raw, decoded, &lastChar);
95 if (success && lastChar != 0) {
96 if (i == 0) {
97 firstDecoded = decoded;
98 }
99 if (lastChar == cpinfo.UnicodeDefaultChar) {
100 restoreDecoded = true;
101 rawparts[id - 1] = *(raw.end() - 1) + rawparts[id - 1];
102 raw.resize(raw.size() - 1);
103 } else {
104 restoreDecoded = false;
105 break;
106 }
107 } else {
108 break;
109 }
110 }
111 if (restoreDecoded) {
112 decoded = firstDecoded;
113 rawparts[id - 1].clear();
114 }
115 }
116 } else {
117 success = DoDecodeText(raw, decoded, NULL);
118 }
119 }
120 return success;
121 #endif
122 }
123
DecodeText(const char * data,size_t length,std::string & decoded,size_t id)124 bool cmProcessOutput::DecodeText(const char* data, size_t length,
125 std::string& decoded, size_t id)
126 {
127 return this->DecodeText(std::string(data, length), decoded, id);
128 }
129
DecodeText(std::vector<char> raw,std::vector<char> & decoded,size_t id)130 bool cmProcessOutput::DecodeText(std::vector<char> raw,
131 std::vector<char>& decoded, size_t id)
132 {
133 std::string str;
134 const bool success =
135 this->DecodeText(std::string(raw.begin(), raw.end()), str, id);
136 decoded.assign(str.begin(), str.end());
137 return success;
138 }
139
140 #if defined(_WIN32)
DoDecodeText(std::string raw,std::string & decoded,wchar_t * lastChar)141 bool cmProcessOutput::DoDecodeText(std::string raw, std::string& decoded,
142 wchar_t* lastChar)
143 {
144 bool success = false;
145 const int wlength =
146 MultiByteToWideChar(codepage, 0, raw.c_str(), int(raw.size()), NULL, 0);
147 auto wdata = cm::make_unique<wchar_t[]>(wlength);
148 int r = MultiByteToWideChar(codepage, 0, raw.c_str(), int(raw.size()),
149 wdata.get(), wlength);
150 if (r > 0) {
151 if (lastChar) {
152 *lastChar = 0;
153 if ((wlength >= 2 && wdata[wlength - 2] != wdata[wlength - 1]) ||
154 wlength >= 1) {
155 *lastChar = wdata[wlength - 1];
156 }
157 }
158 int length = WideCharToMultiByte(defaultCodepage, 0, wdata.get(), wlength,
159 NULL, 0, NULL, NULL);
160 auto data = cm::make_unique<char[]>(length);
161 r = WideCharToMultiByte(defaultCodepage, 0, wdata.get(), wlength,
162 data.get(), length, NULL, NULL);
163 if (r > 0) {
164 decoded = std::string(data.get(), length);
165 success = true;
166 }
167 }
168 return success;
169 }
170 #endif
171