string_generator.hpp 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241
  1. #ifndef BOOST_UUID_STRING_GENERATOR_HPP_INCLUDED
  2. #define BOOST_UUID_STRING_GENERATOR_HPP_INCLUDED
  3. // Copyright 2010 Andy Tompkins
  4. // Copyright 2024 Peter Dimov
  5. // Distributed under the Boost Software License, Version 1.0.
  6. // https://www.boost.org/LICENSE_1_0.txt
  7. #include <boost/uuid/uuid.hpp>
  8. #include <boost/throw_exception.hpp>
  9. #include <boost/config.hpp>
  10. #include <string>
  11. #include <iterator>
  12. #include <algorithm> // for find
  13. #include <stdexcept>
  14. #include <cstring> // for strlen, wcslen
  15. #include <cstdio>
  16. namespace boost {
  17. namespace uuids {
  18. // Generates a UUID from a string
  19. //
  20. // Accepts the following forms:
  21. //
  22. // 0123456789abcdef0123456789abcdef
  23. // 01234567-89ab-cdef-0123-456789abcdef
  24. // {01234567-89ab-cdef-0123-456789abcdef}
  25. // {0123456789abcdef0123456789abcdef}
  26. struct string_generator
  27. {
  28. using result_type = uuid;
  29. template<class Ch, class Traits, class Alloc>
  30. uuid operator()( std::basic_string<Ch, Traits, Alloc> const& s ) const
  31. {
  32. return operator()(s.begin(), s.end());
  33. }
  34. uuid operator()( char const* s ) const
  35. {
  36. return operator()( s, s + std::strlen( s ) );
  37. }
  38. uuid operator()( wchar_t const* s ) const
  39. {
  40. return operator()( s, s + std::wcslen( s ) );
  41. }
  42. template<class CharIterator>
  43. uuid operator()( CharIterator begin, CharIterator end ) const
  44. {
  45. using char_type = typename std::iterator_traits<CharIterator>::value_type;
  46. int ipos = 0;
  47. // check open brace
  48. char_type c = get_next_char( begin, end, ipos );
  49. bool has_open_brace = is_open_brace( c );
  50. char_type open_brace_char = c;
  51. if( has_open_brace )
  52. {
  53. c = get_next_char( begin, end, ipos );
  54. }
  55. bool has_dashes = false;
  56. uuid u;
  57. int i = 0;
  58. for( uuid::iterator it_byte = u.begin(); it_byte != u.end(); ++it_byte, ++i )
  59. {
  60. if( it_byte != u.begin() )
  61. {
  62. c = get_next_char( begin, end, ipos );
  63. }
  64. if( i == 4 )
  65. {
  66. has_dashes = is_dash( c );
  67. if( has_dashes )
  68. {
  69. c = get_next_char( begin, end, ipos );
  70. }
  71. }
  72. else if( i == 6 || i == 8 || i == 10 )
  73. {
  74. // if there are dashes, they must be in every slot
  75. if( has_dashes )
  76. {
  77. if( is_dash( c ) )
  78. {
  79. c = get_next_char( begin, end, ipos );
  80. }
  81. else
  82. {
  83. throw_invalid( ipos - 1, "dash expected" );
  84. }
  85. }
  86. }
  87. *it_byte = get_value( c, ipos - 1 );
  88. c = get_next_char( begin, end, ipos );
  89. *it_byte <<= 4;
  90. *it_byte |= get_value( c, ipos - 1 );
  91. }
  92. // check close brace
  93. if( has_open_brace )
  94. {
  95. c = get_next_char( begin, end, ipos );
  96. check_close_brace( c, open_brace_char, ipos - 1 );
  97. }
  98. // check end of string - any additional data is an invalid uuid
  99. if( begin != end )
  100. {
  101. throw_invalid( ipos, "unexpected extra input" );
  102. }
  103. return u;
  104. }
  105. private:
  106. BOOST_NORETURN void throw_invalid( int ipos, char const* error ) const
  107. {
  108. char buffer[ 16 ];
  109. std::snprintf( buffer, sizeof( buffer ), "%d", ipos );
  110. BOOST_THROW_EXCEPTION( std::runtime_error( std::string( "Invalid UUID string at position " ) + buffer + ": " + error ) );
  111. }
  112. template <typename CharIterator>
  113. typename std::iterator_traits<CharIterator>::value_type
  114. get_next_char( CharIterator& begin, CharIterator end, int& ipos ) const
  115. {
  116. if( begin == end )
  117. {
  118. throw_invalid( ipos, "unexpected end of input" );
  119. }
  120. ++ipos;
  121. return *begin++;
  122. }
  123. unsigned char get_value( char c, int ipos ) const
  124. {
  125. static char const digits_begin[] = "0123456789abcdefABCDEF";
  126. static size_t digits_len = (sizeof(digits_begin) / sizeof(char)) - 1;
  127. static char const* const digits_end = digits_begin + digits_len;
  128. static unsigned char const values[] =
  129. { 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,10,11,12,13,14,15 };
  130. size_t pos = std::find( digits_begin, digits_end, c ) - digits_begin;
  131. if( pos >= digits_len )
  132. {
  133. throw_invalid( ipos, "hex digit expected" );
  134. }
  135. return values[ pos ];
  136. }
  137. unsigned char get_value( wchar_t c, int ipos ) const
  138. {
  139. static wchar_t const digits_begin[] = L"0123456789abcdefABCDEF";
  140. static size_t digits_len = (sizeof(digits_begin) / sizeof(wchar_t)) - 1;
  141. static wchar_t const* const digits_end = digits_begin + digits_len;
  142. static unsigned char const values[] =
  143. { 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,10,11,12,13,14,15 };
  144. size_t pos = std::find( digits_begin, digits_end, c ) - digits_begin;
  145. if( pos >= digits_len )
  146. {
  147. throw_invalid( ipos, "hex digit expected" );
  148. }
  149. return values[ pos ];
  150. }
  151. bool is_dash( char c ) const
  152. {
  153. return c == '-';
  154. }
  155. bool is_dash( wchar_t c ) const
  156. {
  157. return c == L'-';
  158. }
  159. // return closing brace
  160. bool is_open_brace( char c ) const
  161. {
  162. return c == '{';
  163. }
  164. bool is_open_brace( wchar_t c ) const
  165. {
  166. return c == L'{';
  167. }
  168. void check_close_brace( char c, char open_brace, int ipos ) const
  169. {
  170. if( open_brace == '{' && c == '}' )
  171. {
  172. //great
  173. }
  174. else
  175. {
  176. throw_invalid( ipos, "closing brace expected" );
  177. }
  178. }
  179. void check_close_brace( wchar_t c, wchar_t open_brace, int ipos ) const
  180. {
  181. if( open_brace == L'{' && c == L'}' )
  182. {
  183. // great
  184. }
  185. else
  186. {
  187. throw_invalid( ipos, "closing brace expected" );
  188. }
  189. }
  190. };
  191. }} // namespace boost::uuids
  192. #endif // BOOST_UUID_STRING_GENERATOR_HPP_INCLUDED