Url encoding (2)
// // System.Net.HttpUtility // // Author: // Gonzalo Paniagua Javier (gonzalo@novell.com) // // Copyright (c) 2005 Novell, Inc. (http://www.novell.com) // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the // "Software"), to deal in the Software without restriction, including // without limitation the rights to use, copy, modify, merge, publish, // distribute, sublicense, and/or sell copies of the Software, and to // permit persons to whom the Software is furnished to do so, subject to // the following conditions: // // The above copyright notice and this permission notice shall be // included in all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // using System; using System.Globalization; using System.IO; using System.Text; namespace Tavis.Http { public sealed class HttpUtility { private HttpUtility() { } public static string UrlDecode(string s) { return UrlDecode(s, null); } static char[] GetChars(MemoryStream b, Encoding e) { return e.GetChars(b.GetBuffer(), 0, (int)b.Length); } public static string UrlDecode(string s, Encoding e) { if (null == s) return null; if (s.IndexOf('%') == -1 && s.IndexOf('+') == -1) return s; if (e == null) e = Encoding.GetEncoding(28591); StringBuilder output = new StringBuilder(); long len = s.Length; NumberStyles hexa = NumberStyles.HexNumber; MemoryStream bytes = new MemoryStream(); for (int i = 0; i < len; i++) { if (s[i] == '%' && i + 2 < len) { if (s[i + 1] == 'u' && i + 5 < len) { if (bytes.Length > 0) { output.Append(GetChars(bytes, e)); bytes.SetLength(0); } output.Append((char)Int32.Parse(s.Substring(i + 2, 4), hexa)); i += 5; } else { bytes.WriteByte((byte)Int32.Parse(s.Substring(i + 1, 2), hexa)); i += 2; } continue; } if (bytes.Length > 0) { output.Append(GetChars(bytes, e)); bytes.SetLength(0); } if (s[i] == '+') { output.Append(' '); } else { output.Append(s[i]); } } if (bytes.Length > 0) { output.Append(GetChars(bytes, e)); } bytes = null; return output.ToString(); } public static string UrlEncode(string str) { return UrlEncode(str, Encoding.UTF8); } public static string UrlEncode(string s, Encoding Enc) { if (s == null) return null; if (s == "") return ""; byte[] bytes = Enc.GetBytes(s); return Encoding.ASCII.GetString(UrlEncodeToBytes(bytes, 0, bytes.Length)); } public static string UrlEncode(byte[] bytes) { if (bytes == null) return null; if (bytes.Length == 0) return ""; return Encoding.ASCII.GetString(UrlEncodeToBytes(bytes, 0, bytes.Length)); } public static string UrlEncode(byte[] bytes, int offset, int count) { if (bytes == null) return null; if (bytes.Length == 0) return ""; return Encoding.ASCII.GetString(UrlEncodeToBytes(bytes, offset, count)); } public static byte[] UrlEncodeToBytes(string str) { return UrlEncodeToBytes(str, Encoding.UTF8); } public static byte[] UrlEncodeToBytes(string str, Encoding e) { if (str == null) return null; if (str == "") return new byte[0]; byte[] bytes = e.GetBytes(str); return UrlEncodeToBytes(bytes, 0, bytes.Length); } public static byte[] UrlEncodeToBytes(byte[] bytes) { if (bytes == null) return null; if (bytes.Length == 0) return new byte[0]; return UrlEncodeToBytes(bytes, 0, bytes.Length); } static char[] hexChars = "0123456789abcdef".ToCharArray(); const string notEncoded = "!'()*-._"; static void UrlEncodeChar(char c, Stream result, bool isUnicode) { if (c > 255) { //FIXME: what happens when there is an internal error? //if (!isUnicode) // throw new ArgumentOutOfRangeException ("c", c, "c must be less than 256"); int idx; int i = (int)c; result.WriteByte((byte)'%'); result.WriteByte((byte)'u'); idx = i >> 12; result.WriteByte((byte)hexChars[idx]); idx = (i >> 8) & 0x0F; result.WriteByte((byte)hexChars[idx]); idx = (i >> 4) & 0x0F; result.WriteByte((byte)hexChars[idx]); idx = i & 0x0F; result.WriteByte((byte)hexChars[idx]); return; } if (c > ' ' && notEncoded.IndexOf(c) != -1) { 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); } public static byte[] UrlEncodeToBytes(byte[] bytes, int offset, int count) { if (bytes == null) return null; int len = bytes.Length; if (len == 0) return new byte[0]; if (offset < 0 || offset >= len) throw new ArgumentOutOfRangeException("offset"); if (count < 0 || count > len - offset) throw new ArgumentOutOfRangeException("count"); MemoryStream result = new MemoryStream(count); int end = offset + count; for (int i = offset; i < end; i++) UrlEncodeChar((char)bytes[i], result, false); return result.ToArray(); } public static string UrlEncodeUnicode(string str) { if (str == null) return null; return Encoding.ASCII.GetString(UrlEncodeUnicodeToBytes(str)); } public static byte[] UrlEncodeUnicodeToBytes(string str) { if (str == null) return null; if (str == "") return new byte[0]; MemoryStream result = new MemoryStream(str.Length); foreach (char c in str) { UrlEncodeChar(c, result, true); } return result.ToArray(); } } }