33 using uint32_type =
volatile g_uint32_t ;
35 using uint32_type = g_uint32_t ;
38 static constexpr string_view character_map_with_pad(
"=ABCDEFGHIJKLMNOPQRSTUVWXYZ"
39 "abcdefghijklmnopqrstuvwxyz" "0123456789+/" ,
nullptr ) ;
40 static constexpr string_view character_map( character_map_with_pad.data()+1 , character_map_with_pad.size()-1 ) ;
41 static constexpr char pad =
'=' ;
43 static_assert( character_map_with_pad.size() == 1+26+26+10+2 ,
"" ) ;
44 static_assert( character_map.size() == 26+26+10+2 ,
"" ) ;
46 using string_in = string_view ;
47 using iterator_in = string_view::const_iterator ;
48 using iterator_out = std::back_insert_iterator<std::string> ;
50 std::string encode( string_in , string_in eol ) ;
51 std::string decode( string_in ,
bool do_throw ,
bool strict ) ;
52 bool valid( string_in ,
bool strict ) ;
54 void encode_imp( iterator_out , string_in , string_in , std::size_t ) ;
55 void decode_imp( iterator_out , string_in s ,
bool & error ) ;
56 void generate_6( uint32_type & n ,
int & i , iterator_out & ) ;
57 void accumulate_8( uint32_type & n , iterator_in & , iterator_in ,
int & ) ;
58 void accumulate_6( g_uint32_t & n , iterator_in & , iterator_in , std::size_t & ,
bool & error ) ;
59 void generate_8( g_uint32_t & n , std::size_t & i , iterator_out & ,
bool & error ) ;
60 std::size_t index(
char c ,
bool & error ) noexcept ;
61 bool strictlyValid( string_view ) noexcept ;
63 constexpr char to_char( g_uint32_t n )
noexcept
65 return static_cast<char>(
static_cast<unsigned char>(n) ) ;
67 constexpr g_uint32_t numeric(
char c )
noexcept
69 return static_cast<g_uint32_t
>(
static_cast<unsigned char>(c) ) ;
71 constexpr std::size_t hi_6( g_uint32_t n )
noexcept
73 return (n >> 18U) & 0x3FU ;
75 constexpr g_uint32_t hi_8( g_uint32_t n )
noexcept
77 return (n >> 16U) & 0xFFU ;
86 return Base64Imp::encode( {s.data(),s.size()} , {eol.data(),eol.size()} ) ;
91 return Base64Imp::decode( {s.data(),s.size()} , do_throw , strict ) ;
96 return Base64Imp::valid( {s.data(),s.size()} , strict ) ;
101std::string G::Base64Imp::encode( string_in input , string_in eol )
104 result.reserve( input.size() + input.size()/2U ) ;
105 encode_imp( std::back_inserter(result) , input , eol , 19U ) ;
109void G::Base64Imp::encode_imp( iterator_out result_p , string_in input , string_in eol , std::size_t blocks_per_line )
111 std::size_t blocks = 0U ;
112 auto const end = input.end() ;
113 for(
auto p = input.begin() ; p != end ; blocks++ )
115 if( !eol.empty() && blocks != 0U && (blocks % blocks_per_line) == 0U )
116 std::copy( eol.begin() , eol.end() , result_p ) ;
118 uint32_type n = 0UL ;
120 accumulate_8( n , p , end , i ) ;
121 accumulate_8( n , p , end , i ) ;
122 accumulate_8( n , p , end , i ) ;
123 generate_6( n , i , result_p ) ;
124 generate_6( n , i , result_p ) ;
125 generate_6( n , i , result_p ) ;
126 generate_6( n , i , result_p ) ;
130std::string G::Base64Imp::decode( string_in input ,
bool do_throw ,
bool strict )
133 if( strict && !strictlyValid(input) )
137 result.reserve( input.size() ) ;
138 decode_imp( std::back_inserter(result) , input , error ) ;
142 if( error && do_throw )
143 throw Base64::Error() ;
148void G::Base64Imp::decode_imp( iterator_out result_p , string_in s ,
bool & error )
150 auto const end = s.end() ;
151 for(
auto p = s.begin() ; p != end ; )
153 if( *p ==
'\r' || *p ==
'\n' || *p ==
' ' )
161 std::size_t bits = 0U ;
162 accumulate_6( n , p , end , bits , error ) ;
163 accumulate_6( n , p , end , bits , error ) ;
164 accumulate_6( n , p , end , bits , error ) ;
165 accumulate_6( n , p , end , bits , error ) ;
166 if( bits < 8U ) error = true ;
167 generate_8( n , bits , result_p , error ) ;
168 generate_8( n , bits , result_p , error ) ;
169 generate_8( n , bits , result_p , error ) ;
173bool G::Base64Imp::valid( string_in input ,
bool strict )
175 if( strict && !strictlyValid(input) )
180 result.reserve( input.size() ) ;
181 decode_imp( std::back_inserter(result) , input , error ) ;
185bool G::Base64Imp::strictlyValid( string_view s )
noexcept
193 if( std::string::npos == s.find_first_not_of(character_map) )
196 if( std::string::npos != s.find_first_not_of(character_map_with_pad) )
199 std::size_t pos = s.find( pad ) ;
200 if( (pos+1U) == s.size() && s[pos] == pad && (s.size()&3U) == 0U )
203 if( (pos+2U) == s.size() && s[pos] == pad && s[pos+1U] == pad && (s.size()&3U) == 0U )
209void G::Base64Imp::accumulate_8( uint32_type & n , iterator_in & p , iterator_in end ,
int & i )
211 char c = p == end ?
'\0' : *p ;
221void G::Base64Imp::generate_6( uint32_type & n ,
int & i , iterator_out & result )
223 size_t index = hi_6( n ) ;
224 char c = i-- >= 0 ? character_map[index] : pad ;
229void G::Base64Imp::accumulate_6( g_uint32_t & n , iterator_in & p , iterator_in end ,
230 std::size_t & bits ,
bool & error )
242 n |= index( *p++ , error ) ;
247void G::Base64Imp::generate_8( g_uint32_t & n , std::size_t & bits , iterator_out & result ,
bool & error )
252 *result++ = to_char(hi_8(n)) ;
255 else if( hi_8(n) != 0U )
261std::size_t G::Base64Imp::index(
char c ,
bool & error )
noexcept
263 std::size_t pos = character_map.find( c ) ;
264 error = error || (c==
'\0') || pos == std::string::npos ;
265 return pos == std::string::npos ? std::size_t(0) : pos ;
static std::string decode(const std::string &, bool throw_on_invalid=false, bool strict=true)
Decodes the given string.
static std::string encode(const std::string &s, const std::string &line_break=std::string())
Encodes the given string, optionally inserting line-breaks to limit the line length.
static bool valid(const std::string &, bool strict=true)
Returns true if the string is a valid base64 encoding, possibly allowing for embedded newlines,...