Coverage Report

Created: 2026-02-09 06:05

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