1 // Boost string_generator.hpp header file ----------------------------------------------// 2 3 // Copyright 2010 Andy Tompkins. 4 // Distributed under the Boost Software License, Version 1.0. (See 5 // accompanying file LICENSE_1_0.txt or copy at 6 // https://www.boost.org/LICENSE_1_0.txt) 7 8 #ifndef BOOST_UUID_STRING_GENERATOR_HPP 9 #define BOOST_UUID_STRING_GENERATOR_HPP 10 11 #include <boost/uuid/uuid.hpp> 12 #include <string> 13 #include <cstring> // for strlen, wcslen 14 #include <iterator> 15 #include <algorithm> // for find 16 #include <stdexcept> 17 #include <boost/throw_exception.hpp> 18 #include <boost/config.hpp> 19 20 #ifdef BOOST_NO_STDC_NAMESPACE 21 namespace std { 22 using ::strlen; 23 using ::wcslen; 24 } //namespace std 25 #endif //BOOST_NO_STDC_NAMESPACE 26 27 namespace boost { 28 namespace uuids { 29 30 // generate a uuid from a string 31 // lexical_cast works fine using uuid_io.hpp 32 // but this generator should accept more forms 33 // and be more efficient 34 // would like to accept the following forms: 35 // 0123456789abcdef0123456789abcdef 36 // 01234567-89ab-cdef-0123-456789abcdef 37 // {01234567-89ab-cdef-0123-456789abcdef} 38 // {0123456789abcdef0123456789abcdef} 39 // others? 40 struct string_generator { 41 typedef uuid result_type; 42 43 template <typename ch, typename char_traits, typename alloc> operator ()boost::uuids::string_generator44 uuid operator()(std::basic_string<ch, char_traits, alloc> const& s) const { 45 return operator()(s.begin(), s.end()); 46 } 47 operator ()boost::uuids::string_generator48 uuid operator()(char const*const s) const { 49 return operator()(s, s+std::strlen(s)); 50 } 51 operator ()boost::uuids::string_generator52 uuid operator()(wchar_t const*const s) const { 53 return operator()(s, s+std::wcslen(s)); 54 } 55 56 template <typename CharIterator> operator ()boost::uuids::string_generator57 uuid operator()(CharIterator begin, CharIterator end) const 58 { 59 typedef typename std::iterator_traits<CharIterator>::value_type char_type; 60 61 // check open brace 62 char_type c = get_next_char(begin, end); 63 bool has_open_brace = is_open_brace(c); 64 char_type open_brace_char = c; 65 if (has_open_brace) { 66 c = get_next_char(begin, end); 67 } 68 69 bool has_dashes = false; 70 71 uuid u; 72 int i=0; 73 for (uuid::iterator it_byte=u.begin(); it_byte!=u.end(); ++it_byte, ++i) { 74 if (it_byte != u.begin()) { 75 c = get_next_char(begin, end); 76 } 77 78 if (i == 4) { 79 has_dashes = is_dash(c); 80 if (has_dashes) { 81 c = get_next_char(begin, end); 82 } 83 } 84 85 // if there are dashes, they must be in every slot 86 else if (i == 6 || i == 8 || i == 10) { 87 if (has_dashes == true) { 88 if (is_dash(c)) { 89 c = get_next_char(begin, end); 90 } else { 91 throw_invalid(); 92 } 93 } 94 } 95 96 97 *it_byte = get_value(c); 98 99 c = get_next_char(begin, end); 100 *it_byte <<= 4; 101 *it_byte |= get_value(c); 102 } 103 104 // check close brace 105 if (has_open_brace) { 106 c = get_next_char(begin, end); 107 check_close_brace(c, open_brace_char); 108 } 109 110 // check end of string - any additional data is an invalid uuid 111 if (begin != end) { 112 throw_invalid(); 113 } 114 115 return u; 116 } 117 118 private: 119 template <typename CharIterator> 120 typename std::iterator_traits<CharIterator>::value_type get_next_charboost::uuids::string_generator121 get_next_char(CharIterator& begin, CharIterator end) const { 122 if (begin == end) { 123 throw_invalid(); 124 } 125 return *begin++; 126 } 127 get_valueboost::uuids::string_generator128 unsigned char get_value(char c) const { 129 static char const digits_begin[] = "0123456789abcdefABCDEF"; 130 static size_t digits_len = (sizeof(digits_begin) / sizeof(char)) - 1; 131 static char const*const digits_end = digits_begin + digits_len; 132 133 static unsigned char const values[] = 134 { 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,10,11,12,13,14,15 }; 135 136 size_t pos = std::find(digits_begin, digits_end, c) - digits_begin; 137 if (pos >= digits_len) { 138 throw_invalid(); 139 } 140 return values[pos]; 141 } 142 get_valueboost::uuids::string_generator143 unsigned char get_value(wchar_t c) const { 144 static wchar_t const digits_begin[] = L"0123456789abcdefABCDEF"; 145 static size_t digits_len = (sizeof(digits_begin) / sizeof(wchar_t)) - 1; 146 static wchar_t const*const digits_end = digits_begin + digits_len; 147 148 static unsigned char const values[] = 149 { 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,10,11,12,13,14,15 }; 150 151 size_t pos = std::find(digits_begin, digits_end, c) - digits_begin; 152 if (pos >= digits_len) { 153 throw_invalid(); 154 } 155 return values[pos]; 156 } 157 is_dashboost::uuids::string_generator158 bool is_dash(char c) const { 159 return c == '-'; 160 } 161 is_dashboost::uuids::string_generator162 bool is_dash(wchar_t c) const { 163 return c == L'-'; 164 } 165 166 // return closing brace is_open_braceboost::uuids::string_generator167 bool is_open_brace(char c) const { 168 return (c == '{'); 169 } 170 is_open_braceboost::uuids::string_generator171 bool is_open_brace(wchar_t c) const { 172 return (c == L'{'); 173 } 174 check_close_braceboost::uuids::string_generator175 void check_close_brace(char c, char open_brace) const { 176 if (open_brace == '{' && c == '}') { 177 //great 178 } else { 179 throw_invalid(); 180 } 181 } 182 check_close_braceboost::uuids::string_generator183 void check_close_brace(wchar_t c, wchar_t open_brace) const { 184 if (open_brace == L'{' && c == L'}') { 185 // great 186 } else { 187 throw_invalid(); 188 } 189 } 190 throw_invalidboost::uuids::string_generator191 BOOST_NORETURN void throw_invalid() const { 192 BOOST_THROW_EXCEPTION(std::runtime_error("invalid uuid string")); 193 } 194 }; 195 196 }} // namespace boost::uuids 197 198 #endif //BOOST_UUID_STRING_GENERATOR_HPP 199 200