cmProcessOutput.cxx 4.9 KB

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