32 #if defined(G_WINDOWS) && defined(_MSC_VER) && _MSC_VER <= 1929
33 using uint32_type =
volatile g_uint32_t ;
35 using uint32_type = g_uint32_t ;
38 static constexpr std::string_view character_map_with_pad(
"=ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" , 1+26+26+10+2 ) ;
39 static constexpr std::string_view character_map( character_map_with_pad.data()+1 , character_map_with_pad.size()-1 ) ;
40 static constexpr char pad =
'=' ;
42 using iterator_in = std::string_view::const_iterator ;
43 using iterator_out = std::back_insert_iterator<std::string> ;
45 std::string encode( std::string_view , std::string_view eol ) ;
46 std::string decode( std::string_view ,
bool do_throw ,
bool strict ) ;
47 bool valid( std::string_view ,
bool strict ) ;
49 void encode_imp( iterator_out , std::string_view , std::string_view , std::size_t ) ;
50 void decode_imp( iterator_out , std::string_view s ,
bool & error ) ;
51 void generate_6( uint32_type & n ,
int & i , iterator_out & ) ;
52 void accumulate_8( uint32_type & n , iterator_in & , iterator_in ,
int & ) ;
53 void accumulate_6( g_uint32_t & n , iterator_in & , iterator_in , std::size_t & ,
bool & error ) ;
54 void generate_8( g_uint32_t & n , std::size_t & i , iterator_out & ,
bool & error ) ;
55 std::size_t index(
char c ,
bool & error ) noexcept ;
56 bool strictlyValid( std::string_view ) noexcept ;
58 constexpr char to_char( g_uint32_t n )
noexcept
60 return static_cast<char>(
static_cast<unsigned char>(n) ) ;
62 constexpr g_uint32_t numeric(
char c )
noexcept
64 return static_cast<g_uint32_t
>(
static_cast<unsigned char>(c) ) ;
66 constexpr std::size_t hi_6( g_uint32_t n )
noexcept
68 return (n >> 18U) & 0x3FU ;
70 constexpr g_uint32_t hi_8( g_uint32_t n )
noexcept
72 return (n >> 16U) & 0xFFU ;
81 return Base64Imp::encode( s , eol ) ;
86 return Base64Imp::decode( s , do_throw , strict ) ;
91 return Base64Imp::valid( s , strict ) ;
96std::string G::Base64Imp::encode( std::string_view input , std::string_view eol )
99 result.reserve( input.size() + input.size()/2U ) ;
100 encode_imp( std::back_inserter(result) , input , eol , 19U ) ;
104void G::Base64Imp::encode_imp( iterator_out result_p , std::string_view input , std::string_view eol , std::size_t blocks_per_line )
106 std::size_t blocks = 0U ;
107 auto const end = input.end() ;
108 for(
auto p = input.begin() ; p != end ; blocks++ )
110 if( !eol.empty() && blocks != 0U && (blocks % blocks_per_line) == 0U )
111 std::copy( eol.begin() , eol.end() , result_p ) ;
113 uint32_type n = 0UL ;
115 accumulate_8( n , p , end , i ) ;
116 accumulate_8( n , p , end , i ) ;
117 accumulate_8( n , p , end , i ) ;
118 generate_6( n , i , result_p ) ;
119 generate_6( n , i , result_p ) ;
120 generate_6( n , i , result_p ) ;
121 generate_6( n , i , result_p ) ;
125std::string G::Base64Imp::decode( std::string_view input ,
bool do_throw ,
bool strict )
128 if( strict && !strictlyValid(input) )
132 result.reserve( input.size() ) ;
133 decode_imp( std::back_inserter(result) , input , error ) ;
137 if( error && do_throw )
138 throw Base64::Error() ;
143void G::Base64Imp::decode_imp( iterator_out result_p , std::string_view s ,
bool & error )
145 auto const end = s.end() ;
146 for(
auto p = s.begin() ; p != end ; )
148 if( *p ==
'\r' || *p ==
'\n' || *p ==
' ' )
156 std::size_t bits = 0U ;
157 accumulate_6( n , p , end , bits , error ) ;
158 accumulate_6( n , p , end , bits , error ) ;
159 accumulate_6( n , p , end , bits , error ) ;
160 accumulate_6( n , p , end , bits , error ) ;
161 if( bits < 8U ) error = true ;
162 generate_8( n , bits , result_p , error ) ;
163 generate_8( n , bits , result_p , error ) ;
164 generate_8( n , bits , result_p , error ) ;
168bool G::Base64Imp::valid( std::string_view input ,
bool strict )
170 if( strict && !strictlyValid(input) )
175 result.reserve( input.size() ) ;
176 decode_imp( std::back_inserter(result) , input , error ) ;
180bool G::Base64Imp::strictlyValid( std::string_view s )
noexcept
188 if( std::string::npos == s.find_first_not_of(character_map) )
191 if( std::string::npos != s.find_first_not_of(character_map_with_pad) )
194 std::size_t pos = s.find( pad ) ;
195 if( (pos+1U) == s.size() && s[pos] == pad && (s.size()&3U) == 0U )
198 if( (pos+2U) == s.size() && s[pos] == pad && s[pos+1U] == pad && (s.size()&3U) == 0U )
204void G::Base64Imp::accumulate_8( uint32_type & n , iterator_in & p , iterator_in end ,
int & i )
206 char c = p == end ?
'\0' : *p ;
216void G::Base64Imp::generate_6( uint32_type & n ,
int & i , iterator_out & result )
218 size_t index = hi_6( n ) ;
219 char c = i-- >= 0 ? character_map[index] : pad ;
224void G::Base64Imp::accumulate_6( g_uint32_t & n , iterator_in & p , iterator_in end ,
225 std::size_t & bits ,
bool & error )
237 n |= index( *p++ , error ) ;
242void G::Base64Imp::generate_8( g_uint32_t & n , std::size_t & bits , iterator_out & result ,
bool & error )
247 *result++ = to_char(hi_8(n)) ;
250 else if( hi_8(n) != 0U )
256std::size_t G::Base64Imp::index(
char c ,
bool & error )
noexcept
258 std::size_t pos = character_map.find( c ) ;
259 error = error || (c==
'\0') || pos == std::string::npos ;
260 return pos == std::string::npos ? std::size_t(0) : pos ;
static std::string encode(std::string_view, std::string_view line_break={})
Encodes the given string, optionally inserting line-breaks to limit the line length.
static std::string decode(std::string_view, bool throw_on_invalid=false, bool strict=true)
Decodes the given string.
static bool valid(std::string_view, bool strict=true)
Returns true if the string is a valid base64 encoding, possibly allowing for embedded newlines,...