33 using uint32_type =
volatile g_uint32_t ;
35 using uint32_type = g_uint32_t ;
38 static constexpr string_view character_map_with_pad =
"=ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"_sv ;
39 static constexpr string_view character_map( character_map_with_pad.data()+1 , character_map_with_pad.size()-1 ) ;
40 static constexpr char pad =
'=' ;
42 static_assert( character_map_with_pad.size() == 1+26+26+10+2 ,
"" ) ;
43 static_assert( character_map.size() == 26+26+10+2 ,
"" ) ;
45 using iterator_in = string_view::const_iterator ;
46 using iterator_out = std::back_insert_iterator<std::string> ;
48 std::string encode( string_view , string_view eol ) ;
49 std::string decode( string_view ,
bool do_throw ,
bool strict ) ;
50 bool valid( string_view ,
bool strict ) ;
52 void encode_imp( iterator_out , string_view , string_view , std::size_t ) ;
53 void decode_imp( iterator_out , string_view s ,
bool & error ) ;
54 void generate_6( uint32_type & n ,
int & i , iterator_out & ) ;
55 void accumulate_8( uint32_type & n , iterator_in & , iterator_in ,
int & ) ;
56 void accumulate_6( g_uint32_t & n , iterator_in & , iterator_in , std::size_t & ,
bool & error ) ;
57 void generate_8( g_uint32_t & n , std::size_t & i , iterator_out & ,
bool & error ) ;
58 std::size_t index(
char c ,
bool & error ) noexcept ;
59 bool strictlyValid( string_view ) noexcept ;
61 constexpr char to_char( g_uint32_t n )
noexcept
63 return static_cast<char>(
static_cast<unsigned char>(n) ) ;
65 constexpr g_uint32_t numeric(
char c )
noexcept
67 return static_cast<g_uint32_t
>(
static_cast<unsigned char>(c) ) ;
69 constexpr std::size_t hi_6( g_uint32_t n )
noexcept
71 return (n >> 18U) & 0x3FU ;
73 constexpr g_uint32_t hi_8( g_uint32_t n )
noexcept
75 return (n >> 16U) & 0xFFU ;
84 return Base64Imp::encode( s , eol ) ;
89 return Base64Imp::decode( s , do_throw , strict ) ;
94 return Base64Imp::valid( s , strict ) ;
102 result.reserve( input.size() + input.size()/2U ) ;
103 encode_imp( std::back_inserter(result) , input , eol , 19U ) ;
107void G::Base64Imp::encode_imp( iterator_out result_p , string_view input , string_view eol , std::size_t blocks_per_line )
109 std::size_t blocks = 0U ;
110 auto const end = input.end() ;
111 for(
auto p = input.begin() ; p != end ; blocks++ )
113 if( !eol.empty() && blocks != 0U && (blocks % blocks_per_line) == 0U )
114 std::copy( eol.begin() , eol.end() , result_p ) ;
116 uint32_type n = 0UL ;
118 accumulate_8( n , p , end , i ) ;
119 accumulate_8( n , p , end , i ) ;
120 accumulate_8( n , p , end , i ) ;
121 generate_6( n , i , result_p ) ;
122 generate_6( n , i , result_p ) ;
123 generate_6( n , i , result_p ) ;
124 generate_6( n , i , result_p ) ;
128std::string G::Base64Imp::decode( string_view input ,
bool do_throw ,
bool strict )
131 if( strict && !strictlyValid(input) )
135 result.reserve( input.size() ) ;
136 decode_imp( std::back_inserter(result) , input , error ) ;
140 if( error && do_throw )
141 throw Base64::Error() ;
146void G::Base64Imp::decode_imp( iterator_out result_p , string_view s ,
bool & error )
148 auto const end = s.end() ;
149 for(
auto p = s.begin() ; p != end ; )
151 if( *p ==
'\r' || *p ==
'\n' || *p ==
' ' )
159 std::size_t bits = 0U ;
160 accumulate_6( n , p , end , bits , error ) ;
161 accumulate_6( n , p , end , bits , error ) ;
162 accumulate_6( n , p , end , bits , error ) ;
163 accumulate_6( n , p , end , bits , error ) ;
164 if( bits < 8U ) error = true ;
165 generate_8( n , bits , result_p , error ) ;
166 generate_8( n , bits , result_p , error ) ;
167 generate_8( n , bits , result_p , error ) ;
171bool G::Base64Imp::valid( string_view input ,
bool strict )
173 if( strict && !strictlyValid(input) )
178 result.reserve( input.size() ) ;
179 decode_imp( std::back_inserter(result) , input , error ) ;
183bool G::Base64Imp::strictlyValid( string_view s )
noexcept
191 if( std::string::npos == s.find_first_not_of(character_map) )
194 if( std::string::npos != s.find_first_not_of(character_map_with_pad) )
197 std::size_t pos = s.find( pad ) ;
198 if( (pos+1U) == s.size() && s[pos] == pad && (s.size()&3U) == 0U )
201 if( (pos+2U) == s.size() && s[pos] == pad && s[pos+1U] == pad && (s.size()&3U) == 0U )
207void G::Base64Imp::accumulate_8( uint32_type & n , iterator_in & p , iterator_in end ,
int & i )
209 char c = p == end ?
'\0' : *p ;
219void G::Base64Imp::generate_6( uint32_type & n ,
int & i , iterator_out & result )
221 size_t index = hi_6( n ) ;
222 char c = i-- >= 0 ? character_map[index] : pad ;
227void G::Base64Imp::accumulate_6( g_uint32_t & n , iterator_in & p , iterator_in end ,
228 std::size_t & bits ,
bool & error )
240 n |= index( *p++ , error ) ;
245void G::Base64Imp::generate_8( g_uint32_t & n , std::size_t & bits , iterator_out & result ,
bool & error )
250 *result++ = to_char(hi_8(n)) ;
253 else if( hi_8(n) != 0U )
259std::size_t G::Base64Imp::index(
char c ,
bool & error )
noexcept
261 std::size_t pos = character_map.find( c ) ;
262 error = error || (c==
'\0') || pos == std::string::npos ;
263 return pos == std::string::npos ? std::size_t(0) : pos ;
static std::string decode(string_view, bool throw_on_invalid=false, bool strict=true)
Decodes the given string.
static bool valid(string_view, bool strict=true)
Returns true if the string is a valid base64 encoding, possibly allowing for embedded newlines,...
static std::string encode(string_view, string_view line_break={})
Encodes the given string, optionally inserting line-breaks to limit the line length.
A class like c++17's std::string_view.