// // System.Web.HttpUtility/HttpEncoder // // Authors: // Patrik Torstensson (Patrik.Torstensson@labs2.com) // Wictor Wilén (decode/encode functions) (wictor@ibizkit.se) // Tim Coleman (tim@timcoleman.com) using System; using System.Text; using System.IO; using System.Collections.Generic; namespace MonoTorrent { static class UriHelper { static readonly char[] hexChars = "0123456789abcdef".ToCharArray(); public static string UrlEncode(byte[] bytes) { if (bytes == null) throw new ArgumentNullException("bytes"); var result = new MemoryStream(bytes.Length); for (int i = 0; i < bytes.Length; i++) UrlEncodeChar((char)bytes[i], result, false); return Encoding.ASCII.GetString(result.ToArray()); } public static byte[] UrlDecode(string s) { if (null == s) return null; var e = Encoding.UTF8; if (s.IndexOf('%') == -1 && s.IndexOf('+') == -1) return e.GetBytes(s); long len = s.Length; var bytes = new List(); int xchar; char ch; for (int i = 0; i < len; i++) { ch = s[i]; if (ch == '%' && i + 2 < len && s[i + 1] != '%') { if (s[i + 1] == 'u' && i + 5 < len) { // unicode hex sequence xchar = GetChar(s, i + 2, 4); if (xchar != -1) { WriteCharBytes(bytes, (char)xchar, e); i += 5; } else WriteCharBytes(bytes, '%', e); } else if ((xchar = GetChar(s, i + 1, 2)) != -1) { WriteCharBytes(bytes, (char)xchar, e); i += 2; } else { WriteCharBytes(bytes, '%', e); } continue; } if (ch == '+') WriteCharBytes(bytes, ' ', e); else WriteCharBytes(bytes, ch, e); } return bytes.ToArray(); } static void UrlEncodeChar(char c, Stream result, bool isUnicode) { if (c > ' ' && NotEncoded(c)) { result.WriteByte((byte)c); return; } if (c == ' ') { result.WriteByte((byte)'+'); return; } if ((c < '0') || (c < 'A' && c > '9') || (c > 'Z' && c < 'a') || (c > 'z')) { if (isUnicode && c > 127) { result.WriteByte((byte)'%'); result.WriteByte((byte)'u'); result.WriteByte((byte)'0'); result.WriteByte((byte)'0'); } else result.WriteByte((byte)'%'); int idx = ((int)c) >> 4; result.WriteByte((byte)hexChars[idx]); idx = ((int)c) & 0x0F; result.WriteByte((byte)hexChars[idx]); } else { result.WriteByte((byte)c); } } static int GetChar(string str, int offset, int length) { int val = 0; int end = length + offset; for (int i = offset; i < end; i++) { char c = str[i]; if (c > 127) return -1; int current = GetInt((byte)c); if (current == -1) return -1; val = (val << 4) + current; } return val; } static int GetInt(byte b) { char c = (char)b; if (c >= '0' && c <= '9') return c - '0'; if (c >= 'a' && c <= 'f') return c - 'a' + 10; if (c >= 'A' && c <= 'F') return c - 'A' + 10; return -1; } static bool NotEncoded(char c) { return c == '!' || c == '(' || c == ')' || c == '*' || c == '-' || c == '.' || c == '_' || c == '\''; } static void WriteCharBytes(List buf, char ch, Encoding e) { if (ch > 255) { foreach (byte b in e.GetBytes(new char[] { ch })) buf.Add(b); } else buf.Add((byte)ch); } } }