cmQtAutoGeneratorCommon.cxx 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216
  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 "cmQtAutoGeneratorCommon.h"
  4. #include "cmAlgorithms.h"
  5. #include "cmSystemTools.h"
  6. #include "cmsys/FStream.hxx"
  7. #include "cmsys/RegularExpression.hxx"
  8. #include <sstream>
  9. #include <stddef.h>
  10. // - Static functions
  11. static std::string utilStripCR(std::string const& line)
  12. {
  13. // Strip CR characters rcc may have printed (possibly more than one!).
  14. std::string::size_type cr = line.find('\r');
  15. if (cr != std::string::npos) {
  16. return line.substr(0, cr);
  17. }
  18. return line;
  19. }
  20. /// @brief Reads the resource files list from from a .qrc file - Qt4 version
  21. /// @return True if the .qrc file was successfully parsed
  22. static bool RccListInputsQt4(const std::string& fileName,
  23. std::vector<std::string>& files,
  24. std::string* errorMessage)
  25. {
  26. bool allGood = true;
  27. // Read qrc file content into string
  28. std::string qrcContents;
  29. {
  30. cmsys::ifstream ifs(fileName.c_str());
  31. if (ifs) {
  32. std::ostringstream osst;
  33. osst << ifs.rdbuf();
  34. qrcContents = osst.str();
  35. } else {
  36. if (errorMessage != CM_NULLPTR) {
  37. std::ostringstream ost;
  38. ost << "AutoRcc: Error: Rcc file not readable:\n"
  39. << cmQtAutoGeneratorCommon::Quoted(fileName) << "\n";
  40. *errorMessage = ost.str();
  41. }
  42. allGood = false;
  43. }
  44. }
  45. if (allGood) {
  46. // qrc file directory
  47. std::string qrcDir(cmsys::SystemTools::GetFilenamePath(fileName));
  48. if (!qrcDir.empty()) {
  49. qrcDir += '/';
  50. }
  51. cmsys::RegularExpression fileMatchRegex("(<file[^<]+)");
  52. cmsys::RegularExpression fileReplaceRegex("(^<file[^>]*>)");
  53. size_t offset = 0;
  54. while (fileMatchRegex.find(qrcContents.c_str() + offset)) {
  55. std::string qrcEntry = fileMatchRegex.match(1);
  56. offset += qrcEntry.size();
  57. {
  58. fileReplaceRegex.find(qrcEntry);
  59. std::string tag = fileReplaceRegex.match(1);
  60. qrcEntry = qrcEntry.substr(tag.size());
  61. }
  62. if (!cmSystemTools::FileIsFullPath(qrcEntry.c_str())) {
  63. qrcEntry = qrcDir + qrcEntry;
  64. }
  65. files.push_back(qrcEntry);
  66. }
  67. }
  68. return allGood;
  69. }
  70. /// @brief Reads the resource files list from from a .qrc file - Qt5 version
  71. /// @return True if the .qrc file was successfully parsed
  72. static bool RccListInputsQt5(const std::string& rccCommand,
  73. const std::string& fileName,
  74. std::vector<std::string>& files,
  75. std::string* errorMessage)
  76. {
  77. if (rccCommand.empty()) {
  78. cmSystemTools::Error("AutoRcc: Error: rcc executable not available\n");
  79. return false;
  80. }
  81. // Read rcc features
  82. bool hasDashDashList = false;
  83. {
  84. std::vector<std::string> command;
  85. command.push_back(rccCommand);
  86. command.push_back("--help");
  87. std::string rccStdOut;
  88. std::string rccStdErr;
  89. int retVal = 0;
  90. bool result =
  91. cmSystemTools::RunSingleCommand(command, &rccStdOut, &rccStdErr, &retVal,
  92. CM_NULLPTR, cmSystemTools::OUTPUT_NONE);
  93. if (result && retVal == 0 &&
  94. rccStdOut.find("--list") != std::string::npos) {
  95. hasDashDashList = true;
  96. }
  97. }
  98. // Run rcc list command
  99. bool result = false;
  100. int retVal = 0;
  101. std::string rccStdOut;
  102. std::string rccStdErr;
  103. {
  104. std::vector<std::string> command;
  105. command.push_back(rccCommand);
  106. command.push_back(hasDashDashList ? "--list" : "-list");
  107. command.push_back(fileName);
  108. result =
  109. cmSystemTools::RunSingleCommand(command, &rccStdOut, &rccStdErr, &retVal,
  110. CM_NULLPTR, cmSystemTools::OUTPUT_NONE);
  111. }
  112. if (!result || retVal) {
  113. if (errorMessage != CM_NULLPTR) {
  114. std::ostringstream ost;
  115. ost << "AutoRcc: Error: Rcc list process for " << fileName
  116. << " failed:\n"
  117. << rccStdOut << "\n"
  118. << rccStdErr << "\n";
  119. *errorMessage = ost.str();
  120. }
  121. return false;
  122. }
  123. // Parse rcc std output
  124. {
  125. std::istringstream ostr(rccStdOut);
  126. std::string oline;
  127. while (std::getline(ostr, oline)) {
  128. oline = utilStripCR(oline);
  129. if (!oline.empty()) {
  130. files.push_back(oline);
  131. }
  132. }
  133. }
  134. // Parse rcc error output
  135. {
  136. std::istringstream estr(rccStdErr);
  137. std::string eline;
  138. while (std::getline(estr, eline)) {
  139. eline = utilStripCR(eline);
  140. if (cmHasLiteralPrefix(eline, "RCC: Error in")) {
  141. static std::string searchString = "Cannot find file '";
  142. std::string::size_type pos = eline.find(searchString);
  143. if (pos == std::string::npos) {
  144. if (errorMessage != CM_NULLPTR) {
  145. std::ostringstream ost;
  146. ost << "AutoRcc: Error: Rcc lists unparsable output:\n"
  147. << cmQtAutoGeneratorCommon::Quoted(eline) << "\n";
  148. *errorMessage = ost.str();
  149. }
  150. return false;
  151. }
  152. pos += searchString.length();
  153. std::string::size_type sz = eline.size() - pos - 1;
  154. files.push_back(eline.substr(pos, sz));
  155. }
  156. }
  157. }
  158. return true;
  159. }
  160. // - Class definitions
  161. const char* cmQtAutoGeneratorCommon::listSep = "@LSEP@";
  162. std::string cmQtAutoGeneratorCommon::Quoted(const std::string& text)
  163. {
  164. static const char* rep[18] = { "\\", "\\\\", "\"", "\\\"", "\a", "\\a",
  165. "\b", "\\b", "\f", "\\f", "\n", "\\n",
  166. "\r", "\\r", "\t", "\\t", "\v", "\\v" };
  167. std::string res = text;
  168. for (const char* const* it = cmArrayBegin(rep); it != cmArrayEnd(rep);
  169. it += 2) {
  170. cmSystemTools::ReplaceString(res, *it, *(it + 1));
  171. }
  172. res = '"' + res;
  173. res += '"';
  174. return res;
  175. }
  176. bool cmQtAutoGeneratorCommon::RccListInputs(const std::string& qtMajorVersion,
  177. const std::string& rccCommand,
  178. const std::string& fileName,
  179. std::vector<std::string>& files,
  180. std::string* errorMessage)
  181. {
  182. bool allGood = false;
  183. if (cmsys::SystemTools::FileExists(fileName.c_str())) {
  184. if (qtMajorVersion == "4") {
  185. allGood = RccListInputsQt4(fileName, files, errorMessage);
  186. } else {
  187. allGood = RccListInputsQt5(rccCommand, fileName, files, errorMessage);
  188. }
  189. } else {
  190. if (errorMessage != CM_NULLPTR) {
  191. std::ostringstream ost;
  192. ost << "AutoRcc: Error: Rcc file does not exist:\n"
  193. << cmQtAutoGeneratorCommon::Quoted(fileName) << "\n";
  194. *errorMessage = ost.str();
  195. }
  196. }
  197. return allGood;
  198. }