File indexing completed on 2025-07-02 08:30:44
0001 #ifndef BOOST_UUID_STRING_GENERATOR_HPP_INCLUDED
0002 #define BOOST_UUID_STRING_GENERATOR_HPP_INCLUDED
0003
0004
0005
0006
0007
0008
0009 #include <boost/uuid/uuid.hpp>
0010 #include <boost/throw_exception.hpp>
0011 #include <boost/config.hpp>
0012 #include <string>
0013 #include <iterator>
0014 #include <algorithm> // for find
0015 #include <stdexcept>
0016 #include <cstring> // for strlen, wcslen
0017 #include <cstdio>
0018
0019 namespace boost {
0020 namespace uuids {
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031 struct string_generator
0032 {
0033 using result_type = uuid;
0034
0035 template<class Ch, class Traits, class Alloc>
0036 uuid operator()( std::basic_string<Ch, Traits, Alloc> const& s ) const
0037 {
0038 return operator()(s.begin(), s.end());
0039 }
0040
0041 uuid operator()( char const* s ) const
0042 {
0043 return operator()( s, s + std::strlen( s ) );
0044 }
0045
0046 uuid operator()( wchar_t const* s ) const
0047 {
0048 return operator()( s, s + std::wcslen( s ) );
0049 }
0050
0051 template<class CharIterator>
0052 uuid operator()( CharIterator begin, CharIterator end ) const
0053 {
0054 using char_type = typename std::iterator_traits<CharIterator>::value_type;
0055
0056 int ipos = 0;
0057
0058
0059 char_type c = get_next_char( begin, end, ipos );
0060
0061 bool has_open_brace = is_open_brace( c );
0062
0063 char_type open_brace_char = c;
0064
0065 if( has_open_brace )
0066 {
0067 c = get_next_char( begin, end, ipos );
0068 }
0069
0070 bool has_dashes = false;
0071
0072 uuid u;
0073
0074 int i = 0;
0075
0076 for( uuid::iterator it_byte = u.begin(); it_byte != u.end(); ++it_byte, ++i )
0077 {
0078 if( it_byte != u.begin() )
0079 {
0080 c = get_next_char( begin, end, ipos );
0081 }
0082
0083 if( i == 4 )
0084 {
0085 has_dashes = is_dash( c );
0086
0087 if( has_dashes )
0088 {
0089 c = get_next_char( begin, end, ipos );
0090 }
0091 }
0092 else if( i == 6 || i == 8 || i == 10 )
0093 {
0094
0095 if( has_dashes )
0096 {
0097 if( is_dash( c ) )
0098 {
0099 c = get_next_char( begin, end, ipos );
0100 }
0101 else
0102 {
0103 throw_invalid( ipos - 1, "dash expected" );
0104 }
0105 }
0106 }
0107
0108 *it_byte = get_value( c, ipos - 1 );
0109
0110 c = get_next_char( begin, end, ipos );
0111
0112 *it_byte <<= 4;
0113 *it_byte |= get_value( c, ipos - 1 );
0114 }
0115
0116
0117 if( has_open_brace )
0118 {
0119 c = get_next_char( begin, end, ipos );
0120 check_close_brace( c, open_brace_char, ipos - 1 );
0121 }
0122
0123
0124 if( begin != end )
0125 {
0126 throw_invalid( ipos, "unexpected extra input" );
0127 }
0128
0129 return u;
0130 }
0131
0132 private:
0133
0134 BOOST_NORETURN void throw_invalid( int ipos, char const* error ) const
0135 {
0136 char buffer[ 16 ];
0137 std::snprintf( buffer, sizeof( buffer ), "%d", ipos );
0138
0139 BOOST_THROW_EXCEPTION( std::runtime_error( std::string( "Invalid UUID string at position " ) + buffer + ": " + error ) );
0140 }
0141
0142 template <typename CharIterator>
0143 typename std::iterator_traits<CharIterator>::value_type
0144 get_next_char( CharIterator& begin, CharIterator end, int& ipos ) const
0145 {
0146 if( begin == end )
0147 {
0148 throw_invalid( ipos, "unexpected end of input" );
0149 }
0150
0151 ++ipos;
0152 return *begin++;
0153 }
0154
0155 unsigned char get_value( char c, int ipos ) const
0156 {
0157 static char const digits_begin[] = "0123456789abcdefABCDEF";
0158 static size_t digits_len = (sizeof(digits_begin) / sizeof(char)) - 1;
0159 static char const* const digits_end = digits_begin + digits_len;
0160
0161 static unsigned char const values[] =
0162 { 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,10,11,12,13,14,15 };
0163
0164 size_t pos = std::find( digits_begin, digits_end, c ) - digits_begin;
0165
0166 if( pos >= digits_len )
0167 {
0168 throw_invalid( ipos, "hex digit expected" );
0169 }
0170
0171 return values[ pos ];
0172 }
0173
0174 unsigned char get_value( wchar_t c, int ipos ) const
0175 {
0176 static wchar_t const digits_begin[] = L"0123456789abcdefABCDEF";
0177 static size_t digits_len = (sizeof(digits_begin) / sizeof(wchar_t)) - 1;
0178 static wchar_t const* const digits_end = digits_begin + digits_len;
0179
0180 static unsigned char const values[] =
0181 { 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,10,11,12,13,14,15 };
0182
0183 size_t pos = std::find( digits_begin, digits_end, c ) - digits_begin;
0184
0185 if( pos >= digits_len )
0186 {
0187 throw_invalid( ipos, "hex digit expected" );
0188 }
0189
0190 return values[ pos ];
0191 }
0192
0193 bool is_dash( char c ) const
0194 {
0195 return c == '-';
0196 }
0197
0198 bool is_dash( wchar_t c ) const
0199 {
0200 return c == L'-';
0201 }
0202
0203
0204 bool is_open_brace( char c ) const
0205 {
0206 return c == '{';
0207 }
0208
0209 bool is_open_brace( wchar_t c ) const
0210 {
0211 return c == L'{';
0212 }
0213
0214 void check_close_brace( char c, char open_brace, int ipos ) const
0215 {
0216 if( open_brace == '{' && c == '}' )
0217 {
0218
0219 }
0220 else
0221 {
0222 throw_invalid( ipos, "closing brace expected" );
0223 }
0224 }
0225
0226 void check_close_brace( wchar_t c, wchar_t open_brace, int ipos ) const
0227 {
0228 if( open_brace == L'{' && c == L'}' )
0229 {
0230
0231 }
0232 else
0233 {
0234 throw_invalid( ipos, "closing brace expected" );
0235 }
0236 }
0237 };
0238
0239 }}
0240
0241 #endif