summaryrefslogtreecommitdiffstats
path: root/Source
diff options
context:
space:
mode:
authorNils Gladitz <nilsgladitz@gmail.com>2014-08-25 20:44:06 (GMT)
committerNils Gladitz <nilsgladitz@gmail.com>2014-08-28 13:13:54 (GMT)
commit328e8694335ca76fb29ebd5fafe4456a89ac25c7 (patch)
treeebd88c211455ff0a7a1ce8081b1c48bcd01fc214 /Source
parentc2a47a9ac3fef38d9da6260725708c2246c1b9c1 (diff)
downloadCMake-328e8694335ca76fb29ebd5fafe4456a89ac25c7.zip
CMake-328e8694335ca76fb29ebd5fafe4456a89ac25c7.tar.gz
CMake-328e8694335ca76fb29ebd5fafe4456a89ac25c7.tar.bz2
StringUuid: Implement new string(UUID) sub-command.
Diffstat (limited to 'Source')
-rw-r--r--Source/CMakeLists.txt1
-rw-r--r--Source/cmStringCommand.cxx116
-rw-r--r--Source/cmStringCommand.h1
-rw-r--r--Source/cmUuid.cxx214
-rw-r--r--Source/cmUuid.h55
5 files changed, 387 insertions, 0 deletions
diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt
index ff7bc8d..c3f77f4 100644
--- a/Source/CMakeLists.txt
+++ b/Source/CMakeLists.txt
@@ -308,6 +308,7 @@ set(SRCS
cmTest.h
cmTestGenerator.cxx
cmTestGenerator.h
+ cmUuid.cxx
cmVariableWatch.cxx
cmVariableWatch.h
cmVersion.cxx
diff --git a/Source/cmStringCommand.cxx b/Source/cmStringCommand.cxx
index 65912da..90a8f85 100644
--- a/Source/cmStringCommand.cxx
+++ b/Source/cmStringCommand.cxx
@@ -20,6 +20,7 @@
#include <time.h>
#include <cmTimestamp.h>
+#include <cmUuid.h>
//----------------------------------------------------------------------------
bool cmStringCommand
@@ -105,6 +106,10 @@ bool cmStringCommand
{
return this->HandleGenexStripCommand(args);
}
+ else if(subCommand == "UUID")
+ {
+ return this->HandleUuidCommand(args);
+ }
std::string e = "does not recognize sub-command "+subCommand;
this->SetError(e);
@@ -981,3 +986,114 @@ bool cmStringCommand
return true;
}
+
+bool cmStringCommand
+::HandleUuidCommand(std::vector<std::string> const& args)
+{
+#if defined(CMAKE_BUILD_WITH_CMAKE)
+ unsigned int argsIndex = 1;
+
+ if(args.size() < 2)
+ {
+ this->SetError("UUID sub-command requires an output variable.");
+ return false;
+ }
+
+ const std::string &outputVariable = args[argsIndex++];
+
+ std::string uuidNamespaceString;
+ std::string uuidName;
+ std::string uuidType;
+ bool uuidUpperCase = false;
+
+ while(args.size() > argsIndex)
+ {
+ if(args[argsIndex] == "NAMESPACE")
+ {
+ ++argsIndex;
+ if(argsIndex >= args.size())
+ {
+ this->SetError("UUID sub-command, NAMESPACE requires a value.");
+ return false;
+ }
+ uuidNamespaceString = args[argsIndex++];
+ }
+ else if(args[argsIndex] == "NAME")
+ {
+ ++argsIndex;
+ if(argsIndex >= args.size())
+ {
+ this->SetError("UUID sub-command, NAME requires a value.");
+ return false;
+ }
+ uuidName = args[argsIndex++];
+ }
+ else if(args[argsIndex] == "TYPE")
+ {
+ ++argsIndex;
+ if(argsIndex >= args.size())
+ {
+ this->SetError("UUID sub-command, TYPE requires a value.");
+ return false;
+ }
+ uuidType = args[argsIndex++];
+ }
+ else if(args[argsIndex] == "UPPER")
+ {
+ ++argsIndex;
+ uuidUpperCase = true;
+ }
+ else
+ {
+ std::string e = "UUID sub-command does not recognize option " +
+ args[argsIndex] + ".";
+ this->SetError(e);
+ return false;
+ }
+ }
+
+ std::string uuid;
+ cmUuid uuidGenerator;
+
+ std::vector<unsigned char> uuidNamespace;
+ if(!uuidGenerator.StringToBinary(uuidNamespaceString, uuidNamespace))
+ {
+ this->SetError("UUID sub-command, malformed NAMESPACE UUID.");
+ return false;
+ }
+
+ if(uuidType == "MD5")
+ {
+ uuid = uuidGenerator.FromMd5(uuidNamespace, uuidName);
+ }
+ else if(uuidType == "SHA1")
+ {
+ uuid = uuidGenerator.FromSha1(uuidNamespace, uuidName);
+ }
+ else
+ {
+ std::string e = "UUID sub-command, unknown TYPE '" + uuidType + "'.";
+ this->SetError(e);
+ return false;
+ }
+
+ if(uuid.empty())
+ {
+ this->SetError("UUID sub-command, generation failed.");
+ return false;
+ }
+
+ if(uuidUpperCase)
+ {
+ uuid = cmSystemTools::UpperCase(uuid);
+ }
+
+ this->Makefile->AddDefinition(outputVariable, uuid.c_str());
+ return true;
+#else
+ cmOStringStream e;
+ e << args[0] << " not available during bootstrap";
+ this->SetError(e.str().c_str());
+ return false;
+#endif
+}
diff --git a/Source/cmStringCommand.h b/Source/cmStringCommand.h
index 8292e64..9c75095 100644
--- a/Source/cmStringCommand.h
+++ b/Source/cmStringCommand.h
@@ -74,6 +74,7 @@ protected:
bool HandleTimestampCommand(std::vector<std::string> const& args);
bool HandleMakeCIdentifierCommand(std::vector<std::string> const& args);
bool HandleGenexStripCommand(std::vector<std::string> const& args);
+ bool HandleUuidCommand(std::vector<std::string> const& args);
class RegexReplacement
{
diff --git a/Source/cmUuid.cxx b/Source/cmUuid.cxx
new file mode 100644
index 0000000..8b5b7ae
--- /dev/null
+++ b/Source/cmUuid.cxx
@@ -0,0 +1,214 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2014 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmUuid.h"
+
+#include <string.h>
+
+#include <cmsys/MD5.h>
+#include "cm_sha2.h"
+
+cmUuid::cmUuid()
+{
+ Groups.push_back(4);
+ Groups.push_back(2);
+ Groups.push_back(2);
+ Groups.push_back(2);
+ Groups.push_back(6);
+}
+
+std::string cmUuid::FromMd5(std::vector<unsigned char> const& uuidNamespace,
+ std::string const& name) const
+{
+ std::vector<unsigned char> hashInput;
+ this->CreateHashInput(uuidNamespace, name, hashInput);
+
+ cmsysMD5_s *md5 = cmsysMD5_New();
+ cmsysMD5_Initialize(md5);
+ cmsysMD5_Append(md5, &hashInput[0], int(hashInput.size()));
+
+ unsigned char digest[16] = {0};
+ cmsysMD5_Finalize(md5, digest);
+
+ cmsysMD5_Delete(md5);
+
+ return this->FromDigest(digest, 3);
+}
+
+std::string cmUuid::FromSha1(std::vector<unsigned char> const& uuidNamespace,
+ std::string const& name) const
+{
+ std::vector<unsigned char> hashInput;
+ this->CreateHashInput(uuidNamespace, name, hashInput);
+
+ SHA_CTX *sha = new SHA_CTX;
+ SHA1_Init(sha);
+ SHA1_Update(sha, &hashInput[0], hashInput.size());
+
+ unsigned char digest[SHA1_DIGEST_LENGTH] = {0};
+ SHA1_Final(digest, sha);
+
+ delete sha;
+
+ return this->FromDigest(digest, 5);
+}
+
+void cmUuid::CreateHashInput(std::vector<unsigned char> const& uuidNamespace,
+ std::string const& name, std::vector<unsigned char> &output) const
+{
+ output = uuidNamespace;
+
+ if(name.size())
+ {
+ output.resize(output.size() + name.size());
+
+ memcpy(&output[0] + uuidNamespace.size(),
+ name.c_str(), name.size());
+ }
+}
+
+std::string cmUuid::FromDigest(
+ const unsigned char* digest, unsigned char version) const
+{
+ typedef unsigned char byte_t;
+
+ byte_t uuid[16] = {0};
+ memcpy(uuid, digest, 16);
+
+ uuid[6] &= 0xF;
+ uuid[6] |= byte_t(version << 4);
+
+ uuid[8] &= 0x3F;
+ uuid[8] |= 0x80;
+
+ return this->BinaryToString(uuid);
+}
+
+bool cmUuid::StringToBinary(std::string const& input,
+ std::vector<unsigned char> &output) const
+{
+ output.clear();
+ output.reserve(16);
+
+ if(input.length() != 36)
+ {
+ return false;
+ }
+ size_t index = 0;
+ for(size_t i = 0; i < this->Groups.size(); ++i)
+ {
+ if(i != 0 && input[index++] != '-')
+ {
+ return false;
+ }
+ size_t digits = this->Groups[i] * 2;
+ if(!StringToBinaryImpl(input.substr(index, digits), output))
+ {
+ return false;
+ }
+
+ index += digits;
+ }
+
+ return true;
+}
+
+std::string cmUuid::BinaryToString(const unsigned char* input) const
+{
+ std::string output;
+
+ size_t inputIndex = 0;
+ for(size_t i = 0; i < this->Groups.size(); ++i)
+ {
+ if(i != 0)
+ {
+ output += '-';
+ }
+
+ size_t bytes = this->Groups[i];
+ for(size_t j = 0; j < bytes; ++j)
+ {
+ unsigned char byte = input[inputIndex++];
+ output += this->ByteToHex(byte);
+ }
+ }
+
+ return output;
+}
+
+std::string cmUuid::ByteToHex(unsigned char byte) const
+{
+ std::string result;
+ for(int i = 0; i < 2; ++i)
+ {
+ unsigned char rest = byte % 16;
+ byte /= 16;
+
+ char c = (rest < 0xA) ?
+ char('0' + rest) :
+ char('a' + (rest - 0xA));
+
+ result = c + result;
+ }
+
+ return result;
+}
+
+bool cmUuid::StringToBinaryImpl(std::string const& input,
+ std::vector<unsigned char> &output) const
+{
+ if(input.size()%2)
+ {
+ return false;
+ }
+
+ for(size_t i = 0; i < input.size(); i +=2)
+ {
+ char c1 = 0;
+ if(!IntFromHexDigit(input[i], c1))
+ {
+ return false;
+ }
+
+ char c2 = 0;
+ if(!IntFromHexDigit(input[i + 1], c2))
+ {
+ return false;
+ }
+
+ output.push_back(char(c1 << 4 | c2));
+ }
+
+ return true;
+}
+
+bool cmUuid::IntFromHexDigit(char input, char& output) const
+{
+ if(input >= '0' && input <= '9')
+ {
+ output = char(input - '0');
+ return true;
+ }
+ else if(input >= 'a' && input <= 'f')
+ {
+ output = char(input - 'a' + 0xA);
+ return true;
+ }
+ else if(input >= 'A' && input <= 'F')
+ {
+ output = char(input - 'A' + 0xA);
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+}
diff --git a/Source/cmUuid.h b/Source/cmUuid.h
new file mode 100644
index 0000000..0dda357
--- /dev/null
+++ b/Source/cmUuid.h
@@ -0,0 +1,55 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2014 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmUuid_h
+#define cmUuid_h
+
+#include "cmStandardIncludes.h"
+
+/** \class cmUuid
+ * \brief Utility class to generate UUIDs as defined by RFC4122
+ *
+ */
+class cmUuid
+{
+public:
+ cmUuid();
+
+ std::string FromMd5(std::vector<unsigned char> const& uuidNamespace,
+ std::string const& name) const;
+
+ std::string FromSha1(std::vector<unsigned char> const& uuidNamespace,
+ std::string const& name) const;
+
+ bool StringToBinary(std::string const& input,
+ std::vector<unsigned char> &output) const;
+
+private:
+ std::string ByteToHex(unsigned char byte) const;
+
+ void CreateHashInput(std::vector<unsigned char> const& uuidNamespace,
+ std::string const& name, std::vector<unsigned char> &output) const;
+
+ std::string FromDigest(const unsigned char* digest,
+ unsigned char version) const;
+
+ bool StringToBinaryImpl(std::string const& input,
+ std::vector<unsigned char> &output) const;
+
+ std::string BinaryToString(const unsigned char* input) const;
+
+ bool IntFromHexDigit(char input, char& output) const;
+
+ std::vector<int> Groups;
+};
+
+
+#endif