1: using System.Text;
2:
3: namespace System.Web
4: { 5: public sealed class HttpUtility
6: { 7: private static int HexToInt(char h)
8: { 9: if ((h >= '0') && (h <= '9'))
10: { 11: return (h - '0');
12: }
13: if ((h >= 'a') && (h <= 'f'))
14: { 15: return ((h - 'a') + 10);
16: }
17: if ((h >= 'A') && (h <= 'F'))
18: { 19: return ((h - 'A') + 10);
20: }
21: return -1;
22: }
23:
24: internal static char IntToHex(int n)
25: { 26: if (n <= 9)
27: { 28: return (char) (n + 0x30);
29: }
30: return (char) ((n - 10) + 0x61);
31: }
32:
33: private static bool IsNonAsciiByte(byte b)
34: { 35: if (b < 0x7f)
36: { 37: return (b < 0x20);
38: }
39: return true;
40: }
41:
42: internal static bool IsSafe(char ch)
43: { 44: if ((((ch >= 'a') && (ch <= 'z')) || ((ch >= 'A') && (ch <= 'Z'))) || ((ch >= '0') && (ch <= '9')))
45: { 46: return true;
47: }
48: switch (ch)
49: { 50: case '\'':
51: case '(': 52: case ')':
53: case '*':
54: case '-':
55: case '.':
56: case '_':
57: case '!':
58: return true;
59: }
60: return false;
61: }
62:
63: public static string UrlDecode(string str)
64: { 65: if (str == null)
66: { 67: return null;
68: }
69: return UrlDecode(str, Encoding.UTF8);
70: }
71:
72: public static string UrlDecode(byte[] bytes, Encoding e)
73: { 74: if (bytes == null)
75: { 76: return null;
77: }
78: return UrlDecode(bytes, 0, bytes.Length, e);
79: }
80:
81: public static string UrlDecode(string str, Encoding e)
82: { 83: if (str == null)
84: { 85: return null;
86: }
87: return UrlDecodeStringFromStringInternal(str, e);
88: }
89:
90: public static string UrlDecode(byte[] bytes, int offset, int count, Encoding e)
91: { 92: if ((bytes == null) && (count == 0))
93: { 94: return null;
95: }
96: if (bytes == null)
97: { 98: throw new ArgumentNullException("bytes"); 99: }
100: if ((offset < 0) || (offset > bytes.Length))
101: { 102: throw new ArgumentOutOfRangeException("offset"); 103: }
104: if ((count < 0) || ((offset + count) > bytes.Length))
105: { 106: throw new ArgumentOutOfRangeException("count"); 107: }
108: return UrlDecodeStringFromBytesInternal(bytes, offset, count, e);
109: }
110:
111: private static byte[] UrlDecodeBytesFromBytesInternal(byte[] buf, int offset, int count)
112: { 113: int length = 0;
114: byte[] sourceArray = new byte[count];
115: for (int i = 0; i < count; i++)
116: { 117: int index = offset + i;
118: byte num4 = buf[index];
119: if (num4 == 0x2b)
120: { 121: num4 = 0x20;
122: }
123: else if ((num4 == 0x25) && (i < (count - 2)))
124: { 125: int num5 = HexToInt((char) buf[index + 1]);
126: int num6 = HexToInt((char) buf[index + 2]);
127: if ((num5 >= 0) && (num6 >= 0))
128: { 129: num4 = (byte) ((num5 << 4) | num6);
130: i += 2;
131: }
132: }
133: sourceArray[length++] = num4;
134: }
135: if (length < sourceArray.Length)
136: { 137: byte[] destinationArray = new byte[length];
138: Array.Copy(sourceArray, destinationArray, length);
139: sourceArray = destinationArray;
140: }
141: return sourceArray;
142: }
143:
144: private static string UrlDecodeStringFromBytesInternal(byte[] buf, int offset, int count, Encoding e)
145: { 146: UrlDecoder decoder = new UrlDecoder(count, e);
147: for (int i = 0; i < count; i++)
148: { 149: int index = offset + i;
150: byte b = buf[index];
151: if (b == 0x2b)
152: { 153: b = 0x20;
154: }
155: else if ((b == 0x25) && (i < (count - 2)))
156: { 157: if ((buf[index + 1] == 0x75) && (i < (count - 5)))
158: { 159: int num4 = HexToInt((char) buf[index + 2]);
160: int num5 = HexToInt((char) buf[index + 3]);
161: int num6 = HexToInt((char) buf[index + 4]);
162: int num7 = HexToInt((char) buf[index + 5]);
163: if (((num4 < 0) || (num5 < 0)) || ((num6 < 0) || (num7 < 0)))
164: { 165: goto Label_00DA;
166: }
167: char ch = (char) ((((num4 << 12) | (num5 << 8)) | (num6 << 4)) | num7);
168: i += 5;
169: decoder.AddChar(ch);
170: continue;
171: }
172: int num8 = HexToInt((char) buf[index + 1]);
173: int num9 = HexToInt((char) buf[index + 2]);
174: if ((num8 >= 0) && (num9 >= 0))
175: { 176: b = (byte) ((num8 << 4) | num9);
177: i += 2;
178: }
179: }
180: Label_00DA:
181: decoder.AddByte(b);
182: }
183: return decoder.GetString();
184: }
185:
186: private static string UrlDecodeStringFromStringInternal(string s, Encoding e)
187: { 188: int length = s.Length;
189: UrlDecoder decoder = new UrlDecoder(length, e);
190: for (int i = 0; i < length; i++)
191: { 192: char ch = s[i];
193: if (ch == '+')
194: { 195: ch = ' ';
196: }
197: else if ((ch == '%') && (i < (length - 2)))
198: { 199: if ((s[i + 1] == 'u') && (i < (length - 5)))
200: { 201: int num3 = HexToInt(s[i + 2]);
202: int num4 = HexToInt(s[i + 3]);
203: int num5 = HexToInt(s[i + 4]);
204: int num6 = HexToInt(s[i + 5]);
205: if (((num3 < 0) || (num4 < 0)) || ((num5 < 0) || (num6 < 0)))
206: { 207: goto Label_0106;
208: }
209: ch = (char) ((((num3 << 12) | (num4 << 8)) | (num5 << 4)) | num6);
210: i += 5;
211: decoder.AddChar(ch);
212: continue;
213: }
214: int num7 = HexToInt(s[i + 1]);
215: int num8 = HexToInt(s[i + 2]);
216: if ((num7 >= 0) && (num8 >= 0))
217: { 218: byte b = (byte) ((num7 << 4) | num8);
219: i += 2;
220: decoder.AddByte(b);
221: continue;
222: }
223: }
224: Label_0106:
225: if ((ch & 0xff80) == 0)
226: { 227: decoder.AddByte((byte) ch);
228: }
229: else
230: { 231: decoder.AddChar(ch);
232: }
233: }
234: return decoder.GetString();
235: }
236:
237: public static byte[] UrlDecodeToBytes(byte[] bytes)
238: { 239: if (bytes == null)
240: { 241: return null;
242: }
243: return UrlDecodeToBytes(bytes, 0, (bytes != null) ? bytes.Length : 0);
244: }
245:
246: public static byte[] UrlDecodeToBytes(string str)
247: { 248: if (str == null)
249: { 250: return null;
251: }
252: return UrlDecodeToBytes(str, Encoding.UTF8);
253: }
254:
255: public static byte[] UrlDecodeToBytes(string str, Encoding e)
256: { 257: if (str == null)
258: { 259: return null;
260: }
261: return UrlDecodeToBytes(e.GetBytes(str));
262: }
263:
264: public static byte[] UrlDecodeToBytes(byte[] bytes, int offset, int count)
265: { 266: if ((bytes == null) && (count == 0))
267: { 268: return null;
269: }
270: if (bytes == null)
271: { 272: throw new ArgumentNullException("bytes"); 273: }
274: if ((offset < 0) || (offset > bytes.Length))
275: { 276: throw new ArgumentOutOfRangeException("offset"); 277: }
278: if ((count < 0) || ((offset + count) > bytes.Length))
279: { 280: throw new ArgumentOutOfRangeException("count"); 281: }
282: return UrlDecodeBytesFromBytesInternal(bytes, offset, count);
283: }
284:
285: public static string UrlEncode(byte[] bytes)
286: { 287: if (bytes == null)
288: { 289: return null;
290: }
291: return Encoding.ASCII.GetString(UrlEncodeToBytes(bytes));
292: }
293:
294: public static string UrlEncode(string str)
295: { 296: if (str == null)
297: { 298: return null;
299: }
300: return UrlEncode(str, Encoding.UTF8);
301: }
302:
303: public static string UrlEncode(string str, Encoding e)
304: { 305: if (str == null)
306: { 307: return null;
308: }
309: return Encoding.ASCII.GetString(UrlEncodeToBytes(str, e));
310: }
311:
312: public static string UrlEncode(byte[] bytes, int offset, int count)
313: { 314: if (bytes == null)
315: { 316: return null;
317: }
318: return Encoding.ASCII.GetString(UrlEncodeToBytes(bytes, offset, count));
319: }
320:
321: private static byte[] UrlEncodeBytesToBytesInternal(byte[] bytes, int offset, int count,
322: bool alwaysCreateReturnValue)
323: { 324: int num = 0;
325: int num2 = 0;
326: for (int i = 0; i < count; i++)
327: { 328: char ch = (char) bytes[offset + i];
329: if (ch == ' ')
330: { 331: num++;
332: }
333: else if (!IsSafe(ch))
334: { 335: num2++;
336: }
337: }
338: if ((!alwaysCreateReturnValue && (num == 0)) && (num2 == 0))
339: { 340: return bytes;
341: }
342: byte[] buffer = new byte[count + (num2*2)];
343: int num4 = 0;
344: for (int j = 0; j < count; j++)
345: { 346: byte num6 = bytes[offset + j];
347: char ch2 = (char) num6;
348: if (IsSafe(ch2))
349: { 350: buffer[num4++] = num6;
351: }
352: else if (ch2 == ' ')
353: { 354: buffer[num4++] = 0x2b;
355: }
356: else
357: { 358: buffer[num4++] = 0x25;
359: buffer[num4++] = (byte) IntToHex((num6 >> 4) & 15);
360: buffer[num4++] = (byte) IntToHex(num6 & 15);
361: }
362: }
363: return buffer;
364: }
365:
366: private static byte[] UrlEncodeBytesToBytesInternalNonAscii(byte[] bytes, int offset, int count,
367: bool alwaysCreateReturnValue)
368: { 369: int num = 0;
370: for (int i = 0; i < count; i++)
371: { 372: if (IsNonAsciiByte(bytes[offset + i]))
373: { 374: num++;
375: }
376: }
377: if (!alwaysCreateReturnValue && (num == 0))
378: { 379: return bytes;
380: }
381: byte[] buffer = new byte[count + (num*2)];
382: int num3 = 0;
383: for (int j = 0; j < count; j++)
384: { 385: byte b = bytes[offset + j];
386: if (IsNonAsciiByte(b))
387: { 388: buffer[num3++] = 0x25;
389: buffer[num3++] = (byte) IntToHex((b >> 4) & 15);
390: buffer[num3++] = (byte) IntToHex(b & 15);
391: }
392: else
393: { 394: buffer[num3++] = b;
395: }
396: }
397: return buffer;
398: }
399:
400: internal static string UrlEncodeNonAscii(string str, Encoding e)
401: { 402: if (string.IsNullOrEmpty(str))
403: { 404: return str;
405: }
406: if (e == null)
407: { 408: e = Encoding.UTF8;
409: }
410: byte[] bytes = e.GetBytes(str);
411: bytes = UrlEncodeBytesToBytesInternalNonAscii(bytes, 0, bytes.Length, false);
412: return Encoding.ASCII.GetString(bytes);
413: }
414:
415: internal static string UrlEncodeSpaces(string str)
416: { 417: if ((str != null) && (str.IndexOf(' ') >= 0)) 418: { 419: str = str.Replace(" ", "%20"); 420: }
421: return str;
422: }
423:
424: public static byte[] UrlEncodeToBytes(string str)
425: { 426: if (str == null)
427: { 428: return null;
429: }
430: return UrlEncodeToBytes(str, Encoding.UTF8);
431: }
432:
433: public static byte[] UrlEncodeToBytes(byte[] bytes)
434: { 435: if (bytes == null)
436: { 437: return null;
438: }
439: return UrlEncodeToBytes(bytes, 0, bytes.Length);
440: }
441:
442: public static byte[] UrlEncodeToBytes(string str, Encoding e)
443: { 444: if (str == null)
445: { 446: return null;
447: }
448: byte[] bytes = e.GetBytes(str);
449: return UrlEncodeBytesToBytesInternal(bytes, 0, bytes.Length, false);
450: }
451:
452: public static byte[] UrlEncodeToBytes(byte[] bytes, int offset, int count)
453: { 454: if ((bytes == null) && (count == 0))
455: { 456: return null;
457: }
458: if (bytes == null)
459: { 460: throw new ArgumentNullException("bytes"); 461: }
462: if ((offset < 0) || (offset > bytes.Length))
463: { 464: throw new ArgumentOutOfRangeException("offset"); 465: }
466: if ((count < 0) || ((offset + count) > bytes.Length))
467: { 468: throw new ArgumentOutOfRangeException("count"); 469: }
470: return UrlEncodeBytesToBytesInternal(bytes, offset, count, true);
471: }
472:
473: public static string UrlEncodeUnicode(string str)
474: { 475: if (str == null)
476: { 477: return null;
478: }
479: return UrlEncodeUnicodeStringToStringInternal(str, false);
480: }
481:
482: private static string UrlEncodeUnicodeStringToStringInternal(string s, bool ignoreAscii)
483: { 484: int length = s.Length;
485: StringBuilder builder = new StringBuilder(length);
486: for (int i = 0; i < length; i++)
487: { 488: char ch = s[i];
489: if ((ch & 0xff80) == 0)
490: { 491: if (ignoreAscii || IsSafe(ch))
492: { 493: builder.Append(ch);
494: }
495: else if (ch == ' ')
496: { 497: builder.Append('+'); 498: }
499: else
500: { 501: builder.Append('%'); 502: builder.Append(IntToHex((ch >> 4) & '\x000f'));
503: builder.Append(IntToHex(ch & '\x000f'));
504: }
505: }
506: else
507: { 508: builder.Append("%u"); 509: builder.Append(IntToHex((ch >> 12) & '\x000f'));
510: builder.Append(IntToHex((ch >> 8) & '\x000f'));
511: builder.Append(IntToHex((ch >> 4) & '\x000f'));
512: builder.Append(IntToHex(ch & '\x000f'));
513: }
514: }
515: return builder.ToString();
516: }
517:
518: public static byte[] UrlEncodeUnicodeToBytes(string str)
519: { 520: if (str == null)
521: { 522: return null;
523: }
524: return Encoding.ASCII.GetBytes(UrlEncodeUnicode(str));
525: }
526:
527: public static string UrlPathEncode(string str)
528: { 529: if (str == null)
530: { 531: return null;
532: }
533: int index = str.IndexOf('?'); 534: if (index >= 0)
535: { 536: return (UrlPathEncode(str.Substring(0, index)) + str.Substring(index));
537: }
538: return UrlEncodeSpaces(UrlEncodeNonAscii(str, Encoding.UTF8));
539: }
540:
541: // Nested Types
542: private class UrlDecoder
543: { 544: // Fields
545: private int _bufferSize;
546: private byte[] _byteBuffer;
547: private char[] _charBuffer;
548: private Encoding _encoding;
549: private int _numBytes;
550: private int _numChars;
551:
552: // Methods
553: internal UrlDecoder(int bufferSize, Encoding encoding)
554: { 555: _bufferSize = bufferSize;
556: _encoding = encoding;
557: _charBuffer = new char[bufferSize];
558: }
559:
560: internal void AddByte(byte b)
561: { 562: if (_byteBuffer == null)
563: { 564: _byteBuffer = new byte[_bufferSize];
565: }
566: _byteBuffer[_numBytes++] = b;
567: }
568:
569: internal void AddChar(char ch)
570: { 571: if (_numBytes > 0)
572: { 573: FlushBytes();
574: }
575: _charBuffer[_numChars++] = ch;
576: }
577:
578: private void FlushBytes()
579: { 580: if (_numBytes > 0)
581: { 582: _numChars += _encoding.GetChars(_byteBuffer, 0, _numBytes, _charBuffer, _numChars);
583: _numBytes = 0;
584: }
585: }
586:
587: internal string GetString()
588: { 589: if (_numBytes > 0)
590: { 591: FlushBytes();
592: }
593: if (_numChars > 0)
594: { 595: return new string(_charBuffer, 0, _numChars);
596: }
597: return string.Empty;
598: }
599: }
600: }
601: }