1+ //
2+ // Copyright (c) .NET Foundation and Contributors
3+ // Portions Copyright (c) Microsoft Corporation. All rights reserved.
4+ // See LICENSE file in the project root for full license information.
5+ //
6+
7+ using System ;
8+ using System . Text ;
9+
10+ namespace System . Web
11+ {
12+ /// <summary>
13+ /// Utilities to encode and decode url
14+ /// </summary>
15+ public class HttpUtility
16+ {
17+ /// <summary>
18+ /// Encode an URL using UTF8
19+ /// </summary>
20+ /// <param name="str">The URL string to encode</param>
21+ /// <returns>The encoded string URL</returns>
22+ public static string UrlEncode ( string str )
23+ {
24+ if ( ( str == null ) || ( str == string . Empty ) )
25+ {
26+ return string . Empty ;
27+ }
28+
29+ return new string ( Encoding . UTF8 . GetChars ( UrlEncodeToBytes ( str , Encoding . UTF8 ) ) ) ;
30+ }
31+
32+ /// <summary>
33+ /// Encode an URL
34+ /// </summary>
35+ /// <param name="str">The URL string to encode</param>
36+ /// <param name="e">The Encoding object that specifies the encoding scheme</param>
37+ /// <returns>The encoded string URL</returns>
38+ public static string UrlEncode ( string str , Encoding e )
39+ {
40+ if ( ( str == null ) || ( str == string . Empty ) )
41+ {
42+ return string . Empty ;
43+ }
44+
45+ return new string ( e . GetChars ( UrlEncodeToBytes ( str , e ) ) ) ;
46+ }
47+
48+ /// <summary>
49+ /// Encode an URL
50+ /// </summary>
51+ /// <param name="bytes">The array of bytes to encode</param>
52+ /// <param name="offset">The position in the byte array at which to begin encoding</param>
53+ /// <param name="count">The number of bytes to encode</param>
54+ /// <returns>The encoded string URL</returns>
55+ public static string UrlEncode ( byte [ ] bytes , int offset , int count )
56+ {
57+ return new string ( Encoding . UTF8 . GetChars ( UrlEncodeBytesToBytesInternal ( bytes , 0 , bytes . Length , false ) ) ) ;
58+ }
59+
60+ /// <summary>
61+ /// Encode an URL
62+ /// </summary>
63+ /// <param name="bytes">The array of bytes to encode</param>
64+ /// <returns>The encoded string URLL</returns>
65+ public static string UrlEncode ( byte [ ] bytes ) => UrlEncode ( bytes , 0 , bytes . Length ) ;
66+
67+ /// <summary>
68+ /// Encode an URL into a byte array
69+ /// </summary>
70+ /// <param name="str">The URL string to encode</param>
71+ /// <param name="e"></param>
72+ /// <returns>The encoded byte array</returns>
73+ public static byte [ ] UrlEncodeToBytes ( string str , Encoding e )
74+ {
75+ if ( str == null )
76+ {
77+ return null ;
78+ }
79+ var bytes = e . GetBytes ( str ) ;
80+ return UrlEncodeBytesToBytesInternal ( bytes , 0 , bytes . Length , false ) ;
81+ }
82+
83+ /// <summary>
84+ /// Encode a byte array URL into a byte array
85+ /// </summary>
86+ /// <param name="bytes">The array of bytes to encode</param>
87+ /// <returns>The encoded byte array</returns>
88+ public static byte [ ] UrlEncodeToBytes ( byte [ ] bytes ) => UrlEncodeBytesToBytesInternal ( bytes , 0 , bytes . Length , false ) ;
89+
90+ /// <summary>
91+ /// Encode a byte array URL into a byte array
92+ /// </summary>
93+ /// <param name="bytes">The array of bytes to encode</param>
94+ /// <param name="offset">The position in the byte array at which to begin encoding</param>
95+ /// <param name="count">The number of bytes to encode</param>
96+ /// <returns>The encoded byte array</returns>
97+ public static byte [ ] UrlEncodeToBytes ( byte [ ] bytes , int offset , int count ) => UrlEncodeBytesToBytesInternal ( bytes , offset , count , false ) ;
98+
99+ private static byte [ ] UrlEncodeBytesToBytesInternal ( byte [ ] bytes , int offset , int count , bool alwaysCreateReturnValue )
100+ {
101+ var num = 0 ;
102+ var num2 = 0 ;
103+ for ( var i = 0 ; i < count ; i ++ )
104+ {
105+ var ch = ( char ) bytes [ offset + i ] ;
106+ if ( ch == ' ' )
107+ {
108+ num ++ ;
109+ }
110+ else if ( ! IsSafe ( ch ) )
111+ {
112+ num2 ++ ;
113+ }
114+ }
115+ if ( ( ! alwaysCreateReturnValue && ( num == 0 ) ) &&
116+ ( num2 == 0 ) )
117+ {
118+ return bytes ;
119+ }
120+ var buffer = new byte [ count + ( num2 * 2 ) ] ;
121+ var num4 = 0 ;
122+ for ( var j = 0 ; j < count ; j ++ )
123+ {
124+ var num6 = bytes [ offset + j ] ;
125+ var ch2 = ( char ) num6 ;
126+ if ( IsSafe ( ch2 ) )
127+ {
128+ buffer [ num4 ++ ] = num6 ;
129+ }
130+ else if ( ch2 == ' ' )
131+ {
132+ buffer [ num4 ++ ] = 0x2b ;
133+ }
134+ else
135+ {
136+ buffer [ num4 ++ ] = 0x25 ;
137+ buffer [ num4 ++ ] = ( byte ) IntToHex ( ( num6 >> 4 ) & 15 ) ;
138+ buffer [ num4 ++ ] = ( byte ) IntToHex ( num6 & 15 ) ;
139+ }
140+ }
141+ return buffer ;
142+ }
143+
144+ private static char IntToHex ( int n )
145+ {
146+ if ( n <= 9 )
147+ {
148+ return ( char ) ( n + 0x30 ) ;
149+ }
150+ return ( char ) ( ( n - 10 ) + 0x61 ) ;
151+ }
152+
153+ private static bool IsSafe ( char ch )
154+ {
155+ if ( ( ( ( ch >= 'a' ) && ( ch <= 'z' ) ) || ( ( ch >= 'A' ) && ( ch <= 'Z' ) ) ) ||
156+ ( ( ch >= '0' ) && ( ch <= '9' ) ) )
157+ {
158+ return true ;
159+ }
160+ switch ( ch )
161+ {
162+ case '\' ' :
163+ case '(' :
164+ case ')' :
165+ case '*' :
166+ case '-' :
167+ case '.' :
168+ case '_' :
169+ case '!' :
170+ return true ;
171+ }
172+ return false ;
173+ }
174+
175+ /// <summary>
176+ /// Decode an UTF8 encoded URL
177+ /// </summary>
178+ /// <param name="url">The encoded URL</param>
179+ /// <returns>The decoded URL</returns>
180+ public static string UrlDecode ( string url )
181+ {
182+ if ( ( url == null ) || ( url == string . Empty ) )
183+ {
184+ return string . Empty ;
185+ }
186+
187+ var data = Encoding . UTF8 . GetBytes ( url ) ;
188+ return new string ( Encoding . UTF8 . GetChars ( UrlDecodeToBytes ( data , 0 , data . Length ) ) ) ;
189+ }
190+
191+ /// <summary>
192+ /// Decode an URL using the specified encoding
193+ /// </summary>
194+ /// <param name="str">The string to encode</param>
195+ /// <param name="e">The Encoding object that specifies the encoding scheme</param>
196+ /// <returns>The encoded string</returns>
197+ public static string UrlDecode ( string str , Encoding e )
198+ {
199+ if ( ( str == null ) || ( str == string . Empty ) )
200+ {
201+ return string . Empty ;
202+ }
203+
204+ var data = e . GetBytes ( str ) ;
205+ return new string ( e . GetChars ( UrlDecodeToBytes ( data , 0 , data . Length ) ) ) ;
206+ }
207+
208+ /// <summary>
209+ /// Decode an encoded URL
210+ /// </summary>
211+ /// <param name="bytes">The array of bytes to decode</param>
212+ /// <param name="offset">The position in the byte to begin decoding</param>
213+ /// <param name="count">The number of bytes to decode</param>
214+ /// <param name="e">The Encoding object that specifies the encoding scheme</param>
215+ /// <returns>The decoded URL</returns>
216+ public static string UrlDecode ( byte [ ] bytes , int offset , int count , System . Text . Encoding e ) => new string ( e . GetChars ( UrlDecodeToBytes ( bytes , 0 , bytes . Length ) ) ) ;
217+
218+ /// <summary>
219+ /// Decode an encoded URL
220+ /// </summary>
221+ /// <param name="bytes">The array of bytes to decode</param>
222+ /// <param name="e">The Encoding object that specifies the encoding scheme</param>
223+ /// <returns>The decoded URL</returns>
224+ public static string UrlDecode ( byte [ ] bytes , System . Text . Encoding e ) => new string ( e . GetChars ( UrlDecodeToBytes ( bytes , 0 , bytes . Length ) ) ) ;
225+
226+ /// <summary>
227+ /// Decode bytes array to byte array
228+ /// </summary>
229+ /// <param name="bytes">The array of bytes to decode</param>
230+ /// <param name="offset">The position in the byte array at which to begin decoding</param>
231+ /// <param name="count">The number of bytes to decode</param>
232+ /// <returns></returns>
233+ public static byte [ ] UrlDecodeToBytes ( byte [ ] bytes , int offset , int count )
234+ {
235+ var length = 0 ;
236+ var sourceArray = new byte [ count ] ;
237+ for ( var i = 0 ; i < count ; i ++ )
238+ {
239+ var index = offset + i ;
240+ var num4 = bytes [ index ] ;
241+ if ( num4 == 0x2b )
242+ {
243+ num4 = 0x20 ;
244+ }
245+ else if ( ( num4 == 0x25 ) &&
246+ ( i < ( count - 2 ) ) )
247+ {
248+ var num5 = HexToInt ( ( char ) bytes [ index + 1 ] ) ;
249+ var num6 = HexToInt ( ( char ) bytes [ index + 2 ] ) ;
250+ if ( ( num5 >= 0 ) &&
251+ ( num6 >= 0 ) )
252+ {
253+ num4 = ( byte ) ( ( num5 << 4 ) | num6 ) ;
254+ i += 2 ;
255+ }
256+ }
257+ sourceArray [ length ++ ] = num4 ;
258+ }
259+ if ( length < sourceArray . Length )
260+ {
261+ var destinationArray = new byte [ length ] ;
262+ Array . Copy ( sourceArray , destinationArray , length ) ;
263+ sourceArray = destinationArray ;
264+ }
265+ return sourceArray ;
266+ }
267+
268+ /// <summary>
269+ /// Decode bytes array to byte array
270+ /// </summary>
271+ /// <param name="str">The string to encode</param>
272+ /// <param name="e">The Encoding object that specifies the encoding scheme</param>
273+ /// <returns></returns>
274+ public static byte [ ] UrlDecodeToBytes ( string str , System . Text . Encoding e )
275+ {
276+ var data = e . GetBytes ( str ) ;
277+ return UrlDecodeToBytes ( data , 0 , data . Length ) ;
278+ }
279+
280+ /// <summary>
281+ /// Decode bytes array to byte array in UTF8
282+ /// </summary>
283+ /// <param name="str">The string to encode</param>
284+ /// <returns></returns>
285+ public static byte [ ] UrlDecodeToBytes ( string str ) => UrlDecodeToBytes ( str , Encoding . UTF8 ) ;
286+
287+ /// <summary>
288+ /// Decode bytes array to byte array
289+ /// </summary>
290+ /// <param name="bytes">The array of bytes to decode</param>
291+ /// <returns></returns>
292+ public static byte [ ] UrlDecodeToBytes ( byte [ ] bytes ) => UrlDecodeToBytes ( bytes , 0 , bytes . Length ) ;
293+
294+ /// <summary>
295+ /// Get the int value of a char
296+ /// </summary>
297+ /// <param name="h">a char</param>
298+ /// <returns>The int value of the char</returns>
299+ public static int HexToInt ( char h )
300+ {
301+ if ( ( h >= '0' ) &&
302+ ( h <= '9' ) )
303+ {
304+ return ( h - '0' ) ;
305+ }
306+ if ( ( h >= 'a' ) &&
307+ ( h <= 'f' ) )
308+ {
309+ return ( ( h - 'a' ) + 10 ) ;
310+ }
311+ if ( ( h >= 'A' ) &&
312+ ( h <= 'F' ) )
313+ {
314+ return ( ( h - 'A' ) + 10 ) ;
315+ }
316+ return - 1 ;
317+ }
318+ }
319+ }
0 commit comments