• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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