/**
* Licensed under the LGPL, is this code too much like the function
* reencode_escapes in wget/src/urls.c that it should be licensed under
* the GPL?
*/
namespace ISO
{
typedef Size_T std::string::size_type ;
}
bool
is_reserved( const unsigned char c )
{
// Check if the passed char is in the set of reserved chars
const char * found = strchr( "#$&+,.:;=?@[]" , c ) ;
return 0 != found ;
} /* is_reserved( const unsigned char ) */
bool
is_unsafe( const unsigned char c )
{
// Check some outliers in the range of normally unsafe chars
if( strchr( "!$~" , c ) )
{
return false ;
} /* if */
// Check some outliers in the range of normally safe chars
if( strchr( ":<>@[\\]^`" , c ) )
{
return true ;
} /* if */
// Check if we are in the range of unsafe chars
if( ( c <= '%' ) or ( '{' <= c ) )
{
return true ;
} /* if */
return false ;
} /* is_unsafe( const unsigned char ) */
bool
should_escape( const std::string & test , const ISO::Size_T idx )
{
const ISO::Size_T length = test.size() ;
if( length == 0 or length <= idx )
{
return false ;
} /* if */
const char c = test[idx] ;
// Need to check if this is a previously escaped sequence "%xx"
if( '%' == c )
{
// If we haven't 2 digits following, return true (we need to escape) since this can't be "%xx"
if( ( length <= idx + 2 ) or !std::isxdigit( test[idx+1] ) or !std::isxdigit( test[idx+2] ) )
{
return true ;
} /* if */
return false ;
} /* if */
if( is_unsafe( c ) and !is_reserved( c ) )
{
return true ;
} /* if */
return false ;
} /* should_escape( const std::string & , const ISO::Size_T ) */
std::string
escape_url( const std::string & url )
{
std::string result ;
for( ISO::Size_T i = 0 ; i < url.length() ; i++ )
{
// Make this easy to print in a debugger :)
const char curr = url[i] ;
if( should_escape( url , i ) )
{
result += '%' ;
result += ( "0123456789ABCDEF"[(curr >> 4)] ) ;
result += ( "0123456789ABCDEF"[(curr & 0x0F)] ) ;
} /* if */
else
{
// Pass the character through unchanged and unescaped
result += curr ;
} /* else */
} /* for */
return result ;
} /* escape_url( const std::string & ) */