cmFilePathUuid.cxx 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132
  1. /*============================================================================
  2. CMake - Cross Platform Makefile Generator
  3. Copyright 2016 Sebastian Holtermann ([email protected])
  4. Distributed under the OSI-approved BSD License (the "License");
  5. see accompanying file Copyright.txt for details.
  6. This software is distributed WITHOUT ANY WARRANTY; without even the
  7. implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  8. See the License for more information.
  9. ============================================================================*/
  10. #include "cmFilePathUuid.h"
  11. #include "cmCryptoHash.h"
  12. #include "cmMakefile.h"
  13. #include "cmSystemTools.h"
  14. #include "cmsys/Base64.h"
  15. cmFilePathUuid::cmFilePathUuid(cmMakefile* makefile)
  16. {
  17. initParentDirs(makefile->GetCurrentSourceDirectory(),
  18. makefile->GetCurrentBinaryDirectory(),
  19. makefile->GetHomeDirectory(),
  20. makefile->GetHomeOutputDirectory());
  21. }
  22. cmFilePathUuid::cmFilePathUuid(const std::string& currentSrcDir,
  23. const std::string& currentBinDir,
  24. const std::string& projectSrcDir,
  25. const std::string& projectBinDir)
  26. {
  27. initParentDirs(currentSrcDir, currentBinDir, projectSrcDir, projectBinDir);
  28. }
  29. void cmFilePathUuid::initParentDirs(const std::string& currentSrcDir,
  30. const std::string& currentBinDir,
  31. const std::string& projectSrcDir,
  32. const std::string& projectBinDir)
  33. {
  34. parentDirs[0].first = cmsys::SystemTools::GetRealPath(currentSrcDir);
  35. parentDirs[1].first = cmsys::SystemTools::GetRealPath(currentBinDir);
  36. parentDirs[2].first = cmsys::SystemTools::GetRealPath(projectSrcDir);
  37. parentDirs[3].first = cmsys::SystemTools::GetRealPath(projectBinDir);
  38. parentDirs[0].second = "CurrentSource";
  39. parentDirs[1].second = "CurrentBinary";
  40. parentDirs[2].second = "ProjectSource";
  41. parentDirs[3].second = "ProjectBinary";
  42. }
  43. std::string cmFilePathUuid::get(const std::string& filePath,
  44. const char* outputPrefix,
  45. const char* outputSuffix)
  46. {
  47. std::string sourceFilename = cmsys::SystemTools::GetFilenameName(filePath);
  48. std::string sourceBasename =
  49. cmsys::SystemTools::GetFilenameWithoutLastExtension(sourceFilename);
  50. // Acquire checksum string
  51. std::string checksum;
  52. {
  53. std::string sourceRelPath;
  54. std::string sourceRelSeed;
  55. GetRelPathSeed(filePath, sourceRelPath, sourceRelSeed);
  56. checksum = GetChecksumString(sourceFilename, sourceRelPath, sourceRelSeed);
  57. }
  58. // Compose the file name
  59. std::string uuid;
  60. if (outputPrefix) {
  61. uuid += outputPrefix;
  62. }
  63. uuid += sourceBasename.substr(0, partLengthName);
  64. uuid += "_";
  65. uuid += checksum.substr(0, partLengthCheckSum);
  66. if (outputSuffix) {
  67. uuid += outputSuffix;
  68. }
  69. return uuid;
  70. }
  71. void cmFilePathUuid::GetRelPathSeed(const std::string& filePath,
  72. std::string& sourceRelPath,
  73. std::string& sourceRelSeed)
  74. {
  75. const std::string sourceNameReal = cmsys::SystemTools::GetRealPath(filePath);
  76. std::string parentDirectory;
  77. // Find closest project parent directory
  78. for (size_t ii = 0; ii != numParentDirs; ++ii) {
  79. const std::string& pDir = parentDirs[ii].first;
  80. if (!pDir.empty() &&
  81. cmsys::SystemTools::IsSubDirectory(sourceNameReal, pDir)) {
  82. sourceRelSeed = parentDirs[ii].second;
  83. parentDirectory = pDir;
  84. break;
  85. }
  86. }
  87. // Check if the file path is below a known project directory
  88. if (parentDirectory.empty()) {
  89. // Use file syste root as fallback parent directory
  90. sourceRelSeed = "FileSystemRoot";
  91. cmsys::SystemTools::SplitPathRootComponent(sourceNameReal,
  92. &parentDirectory);
  93. }
  94. sourceRelPath = cmsys::SystemTools::RelativePath(
  95. parentDirectory, cmsys::SystemTools::GetParentDirectory(sourceNameReal));
  96. }
  97. std::string cmFilePathUuid::GetChecksumString(
  98. const std::string& sourceFilename, const std::string& sourceRelPath,
  99. const std::string& sourceRelSeed)
  100. {
  101. std::string checksumBase64;
  102. {
  103. // Calculate the file ( seed + relative path + name ) checksum
  104. std::vector<unsigned char> hashBytes =
  105. cmCryptoHash::New("SHA256")->ByteHashString(
  106. (sourceRelSeed + sourceRelPath + sourceFilename).c_str());
  107. // Convert hash bytes to Base64 text string
  108. std::vector<unsigned char> base64Bytes(hashBytes.size() * 2, 0);
  109. cmsysBase64_Encode(&hashBytes[0], hashBytes.size(), &base64Bytes[0], 0);
  110. checksumBase64 = reinterpret_cast<const char*>(&base64Bytes[0]);
  111. }
  112. // Base64 allows '/', '+' and '=' characters which are problematic
  113. // when used in file names. Replace them with safer alternatives.
  114. std::replace(checksumBase64.begin(), checksumBase64.end(), '/', '-');
  115. std::replace(checksumBase64.begin(), checksumBase64.end(), '+', '_');
  116. std::replace(checksumBase64.begin(), checksumBase64.end(), '=', '_');
  117. return checksumBase64;
  118. }