1 // Boost basic_name_generator.hpp header file  -----------------------//
2 
3 // Copyright 2010 Andy Tompkins.
4 // Copyright 2017 James E. King III
5 
6 // Distributed under the Boost Software License, Version 1.0. (See
7 // accompanying file LICENSE_1_0.txt or copy at
8 //  https://www.boost.org/LICENSE_1_0.txt)
9 
10 #ifndef BOOST_UUID_BASIC_NAME_GENERATOR_HPP
11 #define BOOST_UUID_BASIC_NAME_GENERATOR_HPP
12 
13 #include <boost/config.hpp>
14 #include <boost/cstdint.hpp>
15 #include <boost/static_assert.hpp>
16 #include <boost/uuid/uuid.hpp>
17 #include <cstring> // for strlen, wcslen
18 #include <string>
19 
20 #ifdef BOOST_HAS_PRAGMA_ONCE
21 #pragma once
22 #endif
23 
24 #ifdef BOOST_NO_STDC_NAMESPACE
25 namespace std {
26     using ::size_t;
27     using ::strlen;
28     using ::wcslen;
29 } //namespace std
30 #endif //BOOST_NO_STDC_NAMESPACE
31 
32 namespace boost {
33 namespace uuids {
34 
35 //! \brief Generate a name based UUID using
36 //!        the provided hashing algorithm that
37 //!        implements the NameHashProvider concept.
38 template<class HashAlgo>
39 class basic_name_generator
40 {
41   public:
42     typedef uuid result_type;
43     typedef typename HashAlgo::digest_type digest_type;
44 
basic_name_generator(uuid const & namespace_uuid_)45     explicit basic_name_generator(uuid const& namespace_uuid_)
46         : namespace_uuid(namespace_uuid_)
47     {}
48 
operator ()(const char * name) const49     uuid operator()(const char* name) const {
50         HashAlgo hash;
51         hash.process_bytes(namespace_uuid.begin(), namespace_uuid.size());
52         process_characters(hash, name, std::strlen(name));
53         return hash_to_uuid(hash);
54     }
55 
operator ()(const wchar_t * name) const56     uuid operator()(const wchar_t* name) const {
57         HashAlgo hash;
58         hash.process_bytes(namespace_uuid.begin(), namespace_uuid.size());
59         process_characters(hash, name, std::wcslen(name));
60         return hash_to_uuid(hash);
61     }
62 
63     template <typename ch, typename char_traits, typename alloc>
operator ()(std::basic_string<ch,char_traits,alloc> const & name) const64     uuid operator()(std::basic_string<ch, char_traits, alloc> const& name) const {
65         HashAlgo hash;
66         hash.process_bytes(namespace_uuid.begin(), namespace_uuid.size());
67         process_characters(hash, name.c_str(), name.length());
68         return hash_to_uuid(hash);
69     }
70 
operator ()(void const * buffer,std::size_t byte_count) const71     uuid operator()(void const* buffer, std::size_t byte_count) const {
72         HashAlgo hash;
73         hash.process_bytes(namespace_uuid.begin(), namespace_uuid.size());
74         hash.process_bytes(buffer, byte_count);
75         return hash_to_uuid(hash);
76     }
77 
78 private:
79     // we convert all characters to uint32_t so that each
80     // character is 4 bytes regardless of sizeof(char) or
81     // sizeof(wchar_t).  We want the name string on any
82     // platform / compiler to generate the same uuid
83     // except for char
84     template <typename char_type>
process_characters(HashAlgo & hash,char_type const * const characters,std::size_t count) const85     void process_characters(HashAlgo& hash, char_type const*const characters, std::size_t count) const {
86         BOOST_STATIC_ASSERT(sizeof(uint32_t) >= sizeof(char_type));
87 
88         for (std::size_t i=0; i<count; i++) {
89             std::size_t c = characters[i];
90             hash.process_byte(static_cast<unsigned char>((c >>  0) & 0xFF));
91             hash.process_byte(static_cast<unsigned char>((c >>  8) & 0xFF));
92             hash.process_byte(static_cast<unsigned char>((c >> 16) & 0xFF));
93             hash.process_byte(static_cast<unsigned char>((c >> 24) & 0xFF));
94         }
95     }
96 
process_characters(HashAlgo & hash,char const * const characters,std::size_t count) const97     void process_characters(HashAlgo& hash, char const*const characters, std::size_t count) const {
98         hash.process_bytes(characters, count);
99     }
100 
hash_to_uuid(HashAlgo & hash) const101     uuid hash_to_uuid(HashAlgo& hash) const
102     {
103         digest_type digest;
104         hash.get_digest(digest);
105 
106         BOOST_STATIC_ASSERT(sizeof(digest_type) >= 16);
107 
108         uuid u;
109         for (int i=0; i<4; ++i) {
110             *(u.begin() + i*4+0) = static_cast<uint8_t>((digest[i] >> 24) & 0xFF);
111             *(u.begin() + i*4+1) = static_cast<uint8_t>((digest[i] >> 16) & 0xFF);
112             *(u.begin() + i*4+2) = static_cast<uint8_t>((digest[i] >> 8) & 0xFF);
113             *(u.begin() + i*4+3) = static_cast<uint8_t>((digest[i] >> 0) & 0xFF);
114         }
115 
116         // set variant: must be 0b10xxxxxx
117         *(u.begin()+8) &= 0xBF;
118         *(u.begin()+8) |= 0x80;
119 
120         // set version
121         unsigned char hashver = hash.get_version();
122         *(u.begin()+6) &= 0x0F;             // clear out the relevant bits
123         *(u.begin()+6) |= (hashver << 4);   // and apply them
124 
125         return u;
126     }
127 
128 private:
129     uuid namespace_uuid;
130 };
131 
132 namespace ns {
133 
dns()134 BOOST_FORCEINLINE uuid dns() {
135     uuid result = {{
136         0x6b, 0xa7, 0xb8, 0x10, 0x9d, 0xad, 0x11, 0xd1 ,
137         0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8 }};
138     return result;
139 }
140 
url()141 BOOST_FORCEINLINE uuid url() {
142     uuid result = {{
143         0x6b, 0xa7, 0xb8, 0x11, 0x9d, 0xad, 0x11, 0xd1 ,
144         0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8 }};
145     return result;
146 }
147 
oid()148 BOOST_FORCEINLINE uuid oid() {
149     uuid result = {{
150         0x6b, 0xa7, 0xb8, 0x12, 0x9d, 0xad, 0x11, 0xd1 ,
151         0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8 }};
152     return result;
153 }
154 
x500dn()155 BOOST_FORCEINLINE uuid x500dn() {
156     uuid result = {{
157         0x6b, 0xa7, 0xb8, 0x14, 0x9d, 0xad, 0x11, 0xd1 ,
158         0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8 }};
159     return result;
160 }
161 
162 } // ns
163 } // uuids
164 } // boost
165 
166 #endif // BOOST_UUID_BASIC_NAME_GENERATOR_HPP
167