@ -14,105 +14,121 @@ namespace MonoTorrent
{
{
static class UriHelper
static class UriHelper
{
{
static readonly char [ ] hexChars = "0123456789abcdef" . ToCharArray ( ) ;
static readonly char [ ] hexChars = "0123456789abcdef" . ToCharArray ( ) ;
public static string UrlEncode ( byte [ ] bytes )
public static string UrlEncode ( byte [ ] bytes )
{
{
if ( bytes = = null )
if ( bytes = = null )
throw new ArgumentNullException ( "bytes" ) ;
throw new ArgumentNullException ( "bytes" ) ;
var result = new MemoryStream ( bytes . Length ) ;
var result = new MemoryStream ( bytes . Length ) ;
for ( int i = 0 ; i < bytes . Length ; i + + )
for ( int i = 0 ; i < bytes . Length ; i + + )
UrlEncodeChar ( ( char ) bytes [ i ] , result , false ) ;
UrlEncodeChar ( ( char ) bytes [ i ] , result , false ) ;
return Encoding . ASCII . GetString ( result . ToArray ( ) ) ;
return Encoding . ASCII . GetString ( result . ToArray ( ) ) ;
}
}
public static byte [ ] UrlDecode ( string s )
public static byte [ ] UrlDecode ( string s )
{
{
if ( null = = s )
if ( null = = s )
return null ;
return null ;
var e = Encoding . UTF8 ;
var e = Encoding . UTF8 ;
if ( s . IndexOf ( '%' ) = = - 1 & & s . IndexOf ( '+' ) = = - 1 )
if ( s . IndexOf ( '%' ) = = - 1 & & s . IndexOf ( '+' ) = = - 1 )
return e . GetBytes ( s ) ;
return e . GetBytes ( s ) ;
long len = s . Length ;
long len = s . Length ;
var bytes = new List < byte > ( ) ;
var bytes = new List < byte > ( ) ;
int xchar ;
int xchar ;
char ch ;
char ch ;
for ( int i = 0 ; i < len ; i + + ) {
for ( int i = 0 ; i < len ; i + + )
ch = s [ i ] ;
{
if ( ch = = '%' & & i + 2 < len & & s [ i + 1 ] ! = '%' ) {
ch = s [ i ] ;
if ( s [ i + 1 ] = = 'u' & & i + 5 < len ) {
if ( ch = = '%' & & i + 2 < len & & s [ i + 1 ] ! = '%' )
{
if ( s [ i + 1 ] = = 'u' & & i + 5 < len )
{
// unicode hex sequence
// unicode hex sequence
xchar = GetChar ( s , i + 2 , 4 ) ;
xchar = GetChar ( s , i + 2 , 4 ) ;
if ( xchar ! = - 1 ) {
if ( xchar ! = - 1 )
WriteCharBytes ( bytes , ( char ) xchar , e ) ;
{
WriteCharBytes ( bytes , ( char ) xchar , e ) ;
i + = 5 ;
i + = 5 ;
} else
}
WriteCharBytes ( bytes , '%' , e ) ;
else
} else if ( ( xchar = GetChar ( s , i + 1 , 2 ) ) ! = - 1 ) {
WriteCharBytes ( bytes , '%' , e ) ;
WriteCharBytes ( bytes , ( char ) xchar , e ) ;
}
else if ( ( xchar = GetChar ( s , i + 1 , 2 ) ) ! = - 1 )
{
WriteCharBytes ( bytes , ( char ) xchar , e ) ;
i + = 2 ;
i + = 2 ;
} else {
}
WriteCharBytes ( bytes , '%' , e ) ;
else
{
WriteCharBytes ( bytes , '%' , e ) ;
}
}
continue ;
continue ;
}
}
if ( ch = = '+' )
if ( ch = = '+' )
WriteCharBytes ( bytes , ' ' , e ) ;
WriteCharBytes ( bytes , ' ' , e ) ;
else
else
WriteCharBytes ( bytes , ch , e ) ;
WriteCharBytes ( bytes , ch , e ) ;
}
}
return bytes . ToArray ( ) ;
return bytes . ToArray ( ) ;
}
}
static void UrlEncodeChar ( char c , Stream result , bool isUnicode ) {
static void UrlEncodeChar ( char c , Stream result , bool isUnicode )
if ( c > ' ' & & NotEncoded ( c ) ) {
{
result . WriteByte ( ( byte ) c ) ;
if ( c > ' ' & & NotEncoded ( c ) )
{
result . WriteByte ( ( byte ) c ) ;
return ;
return ;
}
}
if ( c = = ' ' ) {
if ( c = = ' ' )
result . WriteByte ( ( byte ) '+' ) ;
{
result . WriteByte ( ( byte ) '+' ) ;
return ;
return ;
}
}
if ( ( c < '0' ) | |
if ( ( c < '0' ) | |
( c < 'A' & & c > '9' ) | |
( c < 'A' & & c > '9' ) | |
( c > 'Z' & & c < 'a' ) | |
( c > 'Z' & & c < 'a' ) | |
( c > 'z' ) ) {
( c > 'z' ) )
if ( isUnicode & & c > 127 ) {
{
result . WriteByte ( ( byte ) '%' ) ;
if ( isUnicode & & c > 127 )
result . WriteByte ( ( byte ) 'u' ) ;
{
result . WriteByte ( ( byte ) '0' ) ;
result . WriteByte ( ( byte ) '%' ) ;
result . WriteByte ( ( byte ) '0' ) ;
result . WriteByte ( ( byte ) 'u' ) ;
result . WriteByte ( ( byte ) '0' ) ;
result . WriteByte ( ( byte ) '0' ) ;
}
}
else
else
result . WriteByte ( ( byte ) '%' ) ;
result . WriteByte ( ( byte ) '%' ) ;
int idx = ( ( int ) c ) > > 4 ;
int idx = ( ( int ) c ) > > 4 ;
result . WriteByte ( ( byte ) hexChars [ idx ] ) ;
result . WriteByte ( ( byte ) hexChars [ idx ] ) ;
idx = ( ( int ) c ) & 0x0F ;
idx = ( ( int ) c ) & 0x0F ;
result . WriteByte ( ( byte ) hexChars [ idx ] ) ;
result . WriteByte ( ( byte ) hexChars [ idx ] ) ;
}
}
else {
else
result . WriteByte ( ( byte ) c ) ;
{
result . WriteByte ( ( byte ) c ) ;
}
}
}
}
static int GetChar ( string str , int offset , int length )
static int GetChar ( string str , int offset , int length )
{
{
int val = 0 ;
int val = 0 ;
int end = length + offset ;
int end = length + offset ;
for ( int i = offset ; i < end ; i + + ) {
for ( int i = offset ; i < end ; i + + )
char c = str [ i ] ;
{
char c = str [ i ] ;
if ( c > 127 )
if ( c > 127 )
return - 1 ;
return - 1 ;
int current = GetInt ( ( byte ) c ) ;
int current = GetInt ( ( byte ) c ) ;
if ( current = = - 1 )
if ( current = = - 1 )
return - 1 ;
return - 1 ;
val = ( val < < 4 ) + current ;
val = ( val < < 4 ) + current ;
@ -121,9 +137,9 @@ namespace MonoTorrent
return val ;
return val ;
}
}
static int GetInt ( byte b )
static int GetInt ( byte b )
{
{
char c = ( char ) b ;
char c = ( char ) b ;
if ( c > = '0' & & c < = '9' )
if ( c > = '0' & & c < = '9' )
return c - '0' ;
return c - '0' ;
@ -136,18 +152,20 @@ namespace MonoTorrent
return - 1 ;
return - 1 ;
}
}
static bool NotEncoded ( char c )
static bool NotEncoded ( char c )
{
{
return c = = '!' | | c = = '(' | | c = = ')' | | c = = '*' | | c = = '-' | | c = = '.' | | c = = '_' | | c = = '\'' ;
return c = = '!' | | c = = '(' | | c = = ')' | | c = = '*' | | c = = '-' | | c = = '.' | | c = = '_' | | c = = '\'' ;
}
}
static void WriteCharBytes ( List < byte > buf , char ch , Encoding e )
static void WriteCharBytes ( List < byte > buf , char ch , Encoding e )
{
{
if ( ch > 255 ) {
if ( ch > 255 )
foreach ( byte b in e . GetBytes ( new char [ ] { ch } ) )
{
buf . Add ( b ) ;
foreach ( byte b in e . GetBytes ( new char [ ] { ch } ) )
} else
buf . Add ( b ) ;
buf . Add ( ( byte ) ch ) ;
}
else
buf . Add ( ( byte ) ch ) ;
}
}
}
}
}
}