Merge pull request #901 from Blewzman/FixAggregateExceptionGetBaseException
[mono.git] / mcs / class / System / System.Net / HttpUtility.cs
1 // 
2 // Copied from System.Web.HttpUtility and marked internal
3 //
4 // Authors:
5 //   Patrik Torstensson (Patrik.Torstensson@labs2.com)
6 //   Wictor WilĂ©n (decode/encode functions) (wictor@ibizkit.se)
7 //   Tim Coleman (tim@timcoleman.com)
8 //   Gonzalo Paniagua Javier (gonzalo@ximian.com)
9 //   Marek Safar (marek.safar@gmail.com)
10 //
11 // Copyright (C) 2005-2009 Novell, Inc (http://www.novell.com)
12 // Copyright (C) 2014 Xamarin Inc (http://www.xamarin.com)
13 //
14 // Permission is hereby granted, free of charge, to any person obtaining
15 // a copy of this software and associated documentation files (the
16 // "Software"), to deal in the Software without restriction, including
17 // without limitation the rights to use, copy, modify, merge, publish,
18 // distribute, sublicense, and/or sell copies of the Software, and to
19 // permit persons to whom the Software is furnished to do so, subject to
20 // the following conditions:
21 // 
22 // The above copyright notice and this permission notice shall be
23 // included in all copies or substantial portions of the Software.
24 // 
25 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
26 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
27 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
28 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
29 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
30 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
31 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
32 //
33
34 using System.Collections;
35 using System.Collections.Generic;
36 using System.Collections.Specialized;
37 using System.Globalization;
38 using System.IO;
39 using System.Security.Permissions;
40 using System.Text;
41
42 namespace System.Net {
43
44         static class HttpUtility
45         {
46                 sealed class HttpQSCollection : NameValueCollection
47                 {
48                         public override string ToString ()
49                         {
50                                 int count = Count;
51                                 if (count == 0)
52                                         return "";
53                                 StringBuilder sb = new StringBuilder ();
54                                 string [] keys = AllKeys;
55                                 for (int i = 0; i < count; i++) {
56                                         sb.AppendFormat ("{0}={1}&", keys [i], this [keys [i]]);
57                                 }
58                                 if (sb.Length > 0)
59                                         sb.Length--;
60                                 return sb.ToString ();
61                         }
62                 }
63
64                 // Must be sorted
65                 static readonly long[] entities = new long[] {
66                         (long)'A' << 56 | (long)'E' << 48 | (long)'l' << 40 | (long)'i' << 32 | (long)'g' << 24, 
67                         (long)'A' << 56 | (long)'a' << 48 | (long)'c' << 40 | (long)'u' << 32 | (long)'t' << 24 | (long)'e' << 16, 
68                         (long)'A' << 56 | (long)'c' << 48 | (long)'i' << 40 | (long)'r' << 32 | (long)'c' << 24, 
69                         (long)'A' << 56 | (long)'g' << 48 | (long)'r' << 40 | (long)'a' << 32 | (long)'v' << 24 | (long)'e' << 16, 
70                         (long)'A' << 56 | (long)'l' << 48 | (long)'p' << 40 | (long)'h' << 32 | (long)'a' << 24, 
71                         (long)'A' << 56 | (long)'r' << 48 | (long)'i' << 40 | (long)'n' << 32 | (long)'g' << 24, 
72                         (long)'A' << 56 | (long)'t' << 48 | (long)'i' << 40 | (long)'l' << 32 | (long)'d' << 24 | (long)'e' << 16, 
73                         (long)'A' << 56 | (long)'u' << 48 | (long)'m' << 40 | (long)'l' << 32, 
74                         (long)'B' << 56 | (long)'e' << 48 | (long)'t' << 40 | (long)'a' << 32, 
75                         (long)'C' << 56 | (long)'c' << 48 | (long)'e' << 40 | (long)'d' << 32 | (long)'i' << 24 | (long)'l' << 16, 
76                         (long)'C' << 56 | (long)'h' << 48 | (long)'i' << 40, 
77                         (long)'D' << 56 | (long)'a' << 48 | (long)'g' << 40 | (long)'g' << 32 | (long)'e' << 24 | (long)'r' << 16, 
78                         (long)'D' << 56 | (long)'e' << 48 | (long)'l' << 40 | (long)'t' << 32 | (long)'a' << 24, 
79                         (long)'E' << 56 | (long)'T' << 48 | (long)'H' << 40, 
80                         (long)'E' << 56 | (long)'a' << 48 | (long)'c' << 40 | (long)'u' << 32 | (long)'t' << 24 | (long)'e' << 16, 
81                         (long)'E' << 56 | (long)'c' << 48 | (long)'i' << 40 | (long)'r' << 32 | (long)'c' << 24, 
82                         (long)'E' << 56 | (long)'g' << 48 | (long)'r' << 40 | (long)'a' << 32 | (long)'v' << 24 | (long)'e' << 16, 
83                         (long)'E' << 56 | (long)'p' << 48 | (long)'s' << 40 | (long)'i' << 32 | (long)'l' << 24 | (long)'o' << 16 | (long)'n' << 8, 
84                         (long)'E' << 56 | (long)'t' << 48 | (long)'a' << 40, 
85                         (long)'E' << 56 | (long)'u' << 48 | (long)'m' << 40 | (long)'l' << 32, 
86                         (long)'G' << 56 | (long)'a' << 48 | (long)'m' << 40 | (long)'m' << 32 | (long)'a' << 24, 
87                         (long)'I' << 56 | (long)'a' << 48 | (long)'c' << 40 | (long)'u' << 32 | (long)'t' << 24 | (long)'e' << 16, 
88                         (long)'I' << 56 | (long)'c' << 48 | (long)'i' << 40 | (long)'r' << 32 | (long)'c' << 24, 
89                         (long)'I' << 56 | (long)'g' << 48 | (long)'r' << 40 | (long)'a' << 32 | (long)'v' << 24 | (long)'e' << 16, 
90                         (long)'I' << 56 | (long)'o' << 48 | (long)'t' << 40 | (long)'a' << 32, 
91                         (long)'I' << 56 | (long)'u' << 48 | (long)'m' << 40 | (long)'l' << 32, 
92                         (long)'K' << 56 | (long)'a' << 48 | (long)'p' << 40 | (long)'p' << 32 | (long)'a' << 24, 
93                         (long)'L' << 56 | (long)'a' << 48 | (long)'m' << 40 | (long)'b' << 32 | (long)'d' << 24 | (long)'a' << 16, 
94                         (long)'M' << 56 | (long)'u' << 48, 
95                         (long)'N' << 56 | (long)'t' << 48 | (long)'i' << 40 | (long)'l' << 32 | (long)'d' << 24 | (long)'e' << 16, 
96                         (long)'N' << 56 | (long)'u' << 48, 
97                         (long)'O' << 56 | (long)'E' << 48 | (long)'l' << 40 | (long)'i' << 32 | (long)'g' << 24, 
98                         (long)'O' << 56 | (long)'a' << 48 | (long)'c' << 40 | (long)'u' << 32 | (long)'t' << 24 | (long)'e' << 16, 
99                         (long)'O' << 56 | (long)'c' << 48 | (long)'i' << 40 | (long)'r' << 32 | (long)'c' << 24, 
100                         (long)'O' << 56 | (long)'g' << 48 | (long)'r' << 40 | (long)'a' << 32 | (long)'v' << 24 | (long)'e' << 16, 
101                         (long)'O' << 56 | (long)'m' << 48 | (long)'e' << 40 | (long)'g' << 32 | (long)'a' << 24, 
102                         (long)'O' << 56 | (long)'m' << 48 | (long)'i' << 40 | (long)'c' << 32 | (long)'r' << 24 | (long)'o' << 16 | (long)'n' << 8, 
103                         (long)'O' << 56 | (long)'s' << 48 | (long)'l' << 40 | (long)'a' << 32 | (long)'s' << 24 | (long)'h' << 16, 
104                         (long)'O' << 56 | (long)'t' << 48 | (long)'i' << 40 | (long)'l' << 32 | (long)'d' << 24 | (long)'e' << 16, 
105                         (long)'O' << 56 | (long)'u' << 48 | (long)'m' << 40 | (long)'l' << 32, 
106                         (long)'P' << 56 | (long)'h' << 48 | (long)'i' << 40, 
107                         (long)'P' << 56 | (long)'i' << 48, 
108                         (long)'P' << 56 | (long)'r' << 48 | (long)'i' << 40 | (long)'m' << 32 | (long)'e' << 24, 
109                         (long)'P' << 56 | (long)'s' << 48 | (long)'i' << 40, 
110                         (long)'R' << 56 | (long)'h' << 48 | (long)'o' << 40, 
111                         (long)'S' << 56 | (long)'c' << 48 | (long)'a' << 40 | (long)'r' << 32 | (long)'o' << 24 | (long)'n' << 16, 
112                         (long)'S' << 56 | (long)'i' << 48 | (long)'g' << 40 | (long)'m' << 32 | (long)'a' << 24, 
113                         (long)'T' << 56 | (long)'H' << 48 | (long)'O' << 40 | (long)'R' << 32 | (long)'N' << 24, 
114                         (long)'T' << 56 | (long)'a' << 48 | (long)'u' << 40, 
115                         (long)'T' << 56 | (long)'h' << 48 | (long)'e' << 40 | (long)'t' << 32 | (long)'a' << 24, 
116                         (long)'U' << 56 | (long)'a' << 48 | (long)'c' << 40 | (long)'u' << 32 | (long)'t' << 24 | (long)'e' << 16, 
117                         (long)'U' << 56 | (long)'c' << 48 | (long)'i' << 40 | (long)'r' << 32 | (long)'c' << 24, 
118                         (long)'U' << 56 | (long)'g' << 48 | (long)'r' << 40 | (long)'a' << 32 | (long)'v' << 24 | (long)'e' << 16, 
119                         (long)'U' << 56 | (long)'p' << 48 | (long)'s' << 40 | (long)'i' << 32 | (long)'l' << 24 | (long)'o' << 16 | (long)'n' << 8, 
120                         (long)'U' << 56 | (long)'u' << 48 | (long)'m' << 40 | (long)'l' << 32, 
121                         (long)'X' << 56 | (long)'i' << 48, 
122                         (long)'Y' << 56 | (long)'a' << 48 | (long)'c' << 40 | (long)'u' << 32 | (long)'t' << 24 | (long)'e' << 16, 
123                         (long)'Y' << 56 | (long)'u' << 48 | (long)'m' << 40 | (long)'l' << 32, 
124                         (long)'Z' << 56 | (long)'e' << 48 | (long)'t' << 40 | (long)'a' << 32, 
125                         (long)'a' << 56 | (long)'a' << 48 | (long)'c' << 40 | (long)'u' << 32 | (long)'t' << 24 | (long)'e' << 16, 
126                         (long)'a' << 56 | (long)'c' << 48 | (long)'i' << 40 | (long)'r' << 32 | (long)'c' << 24, 
127                         (long)'a' << 56 | (long)'c' << 48 | (long)'u' << 40 | (long)'t' << 32 | (long)'e' << 24, 
128                         (long)'a' << 56 | (long)'e' << 48 | (long)'l' << 40 | (long)'i' << 32 | (long)'g' << 24, 
129                         (long)'a' << 56 | (long)'g' << 48 | (long)'r' << 40 | (long)'a' << 32 | (long)'v' << 24 | (long)'e' << 16, 
130                         (long)'a' << 56 | (long)'l' << 48 | (long)'e' << 40 | (long)'f' << 32 | (long)'s' << 24 | (long)'y' << 16 | (long)'m' << 8, 
131                         (long)'a' << 56 | (long)'l' << 48 | (long)'p' << 40 | (long)'h' << 32 | (long)'a' << 24, 
132                         (long)'a' << 56 | (long)'m' << 48 | (long)'p' << 40, 
133                         (long)'a' << 56 | (long)'n' << 48 | (long)'d' << 40, 
134                         (long)'a' << 56 | (long)'n' << 48 | (long)'g' << 40, 
135                         (long)'a' << 56 | (long)'p' << 48 | (long)'o' << 40 | (long)'s' << 32,
136                         (long)'a' << 56 | (long)'r' << 48 | (long)'i' << 40 | (long)'n' << 32 | (long)'g' << 24, 
137                         (long)'a' << 56 | (long)'s' << 48 | (long)'y' << 40 | (long)'m' << 32 | (long)'p' << 24, 
138                         (long)'a' << 56 | (long)'t' << 48 | (long)'i' << 40 | (long)'l' << 32 | (long)'d' << 24 | (long)'e' << 16, 
139                         (long)'a' << 56 | (long)'u' << 48 | (long)'m' << 40 | (long)'l' << 32, 
140                         (long)'b' << 56 | (long)'d' << 48 | (long)'q' << 40 | (long)'u' << 32 | (long)'o' << 24, 
141                         (long)'b' << 56 | (long)'e' << 48 | (long)'t' << 40 | (long)'a' << 32, 
142                         (long)'b' << 56 | (long)'r' << 48 | (long)'v' << 40 | (long)'b' << 32 | (long)'a' << 24 | (long)'r' << 16, 
143                         (long)'b' << 56 | (long)'u' << 48 | (long)'l' << 40 | (long)'l' << 32, 
144                         (long)'c' << 56 | (long)'a' << 48 | (long)'p' << 40, 
145                         (long)'c' << 56 | (long)'c' << 48 | (long)'e' << 40 | (long)'d' << 32 | (long)'i' << 24 | (long)'l' << 16, 
146                         (long)'c' << 56 | (long)'e' << 48 | (long)'d' << 40 | (long)'i' << 32 | (long)'l' << 24, 
147                         (long)'c' << 56 | (long)'e' << 48 | (long)'n' << 40 | (long)'t' << 32, 
148                         (long)'c' << 56 | (long)'h' << 48 | (long)'i' << 40, 
149                         (long)'c' << 56 | (long)'i' << 48 | (long)'r' << 40 | (long)'c' << 32, 
150                         (long)'c' << 56 | (long)'l' << 48 | (long)'u' << 40 | (long)'b' << 32 | (long)'s' << 24, 
151                         (long)'c' << 56 | (long)'o' << 48 | (long)'n' << 40 | (long)'g' << 32, 
152                         (long)'c' << 56 | (long)'o' << 48 | (long)'p' << 40 | (long)'y' << 32, 
153                         (long)'c' << 56 | (long)'r' << 48 | (long)'a' << 40 | (long)'r' << 32 | (long)'r' << 24, 
154                         (long)'c' << 56 | (long)'u' << 48 | (long)'p' << 40, 
155                         (long)'c' << 56 | (long)'u' << 48 | (long)'r' << 40 | (long)'r' << 32 | (long)'e' << 24 | (long)'n' << 16, 
156                         (long)'d' << 56 | (long)'A' << 48 | (long)'r' << 40 | (long)'r' << 32, 
157                         (long)'d' << 56 | (long)'a' << 48 | (long)'g' << 40 | (long)'g' << 32 | (long)'e' << 24 | (long)'r' << 16, 
158                         (long)'d' << 56 | (long)'a' << 48 | (long)'r' << 40 | (long)'r' << 32, 
159                         (long)'d' << 56 | (long)'e' << 48 | (long)'g' << 40, 
160                         (long)'d' << 56 | (long)'e' << 48 | (long)'l' << 40 | (long)'t' << 32 | (long)'a' << 24, 
161                         (long)'d' << 56 | (long)'i' << 48 | (long)'a' << 40 | (long)'m' << 32 | (long)'s' << 24, 
162                         (long)'d' << 56 | (long)'i' << 48 | (long)'v' << 40 | (long)'i' << 32 | (long)'d' << 24 | (long)'e' << 16, 
163                         (long)'e' << 56 | (long)'a' << 48 | (long)'c' << 40 | (long)'u' << 32 | (long)'t' << 24 | (long)'e' << 16, 
164                         (long)'e' << 56 | (long)'c' << 48 | (long)'i' << 40 | (long)'r' << 32 | (long)'c' << 24, 
165                         (long)'e' << 56 | (long)'g' << 48 | (long)'r' << 40 | (long)'a' << 32 | (long)'v' << 24 | (long)'e' << 16, 
166                         (long)'e' << 56 | (long)'m' << 48 | (long)'p' << 40 | (long)'t' << 32 | (long)'y' << 24, 
167                         (long)'e' << 56 | (long)'m' << 48 | (long)'s' << 40 | (long)'p' << 32, 
168                         (long)'e' << 56 | (long)'n' << 48 | (long)'s' << 40 | (long)'p' << 32, 
169                         (long)'e' << 56 | (long)'p' << 48 | (long)'s' << 40 | (long)'i' << 32 | (long)'l' << 24 | (long)'o' << 16 | (long)'n' << 8, 
170                         (long)'e' << 56 | (long)'q' << 48 | (long)'u' << 40 | (long)'i' << 32 | (long)'v' << 24, 
171                         (long)'e' << 56 | (long)'t' << 48 | (long)'a' << 40, 
172                         (long)'e' << 56 | (long)'t' << 48 | (long)'h' << 40, 
173                         (long)'e' << 56 | (long)'u' << 48 | (long)'m' << 40 | (long)'l' << 32, 
174                         (long)'e' << 56 | (long)'u' << 48 | (long)'r' << 40 | (long)'o' << 32, 
175                         (long)'e' << 56 | (long)'x' << 48 | (long)'i' << 40 | (long)'s' << 32 | (long)'t' << 24, 
176                         (long)'f' << 56 | (long)'n' << 48 | (long)'o' << 40 | (long)'f' << 32, 
177                         (long)'f' << 56 | (long)'o' << 48 | (long)'r' << 40 | (long)'a' << 32 | (long)'l' << 24 | (long)'l' << 16, 
178                         (long)'f' << 56 | (long)'r' << 48 | (long)'a' << 40 | (long)'c' << 32 | (long)'1' << 24 | (long)'2' << 16, 
179                         (long)'f' << 56 | (long)'r' << 48 | (long)'a' << 40 | (long)'c' << 32 | (long)'1' << 24 | (long)'4' << 16, 
180                         (long)'f' << 56 | (long)'r' << 48 | (long)'a' << 40 | (long)'c' << 32 | (long)'3' << 24 | (long)'4' << 16, 
181                         (long)'f' << 56 | (long)'r' << 48 | (long)'a' << 40 | (long)'s' << 32 | (long)'l' << 24, 
182                         (long)'g' << 56 | (long)'a' << 48 | (long)'m' << 40 | (long)'m' << 32 | (long)'a' << 24, 
183                         (long)'g' << 56 | (long)'e' << 48, 
184                         (long)'g' << 56 | (long)'t' << 48, 
185                         (long)'h' << 56 | (long)'A' << 48 | (long)'r' << 40 | (long)'r' << 32, 
186                         (long)'h' << 56 | (long)'a' << 48 | (long)'r' << 40 | (long)'r' << 32, 
187                         (long)'h' << 56 | (long)'e' << 48 | (long)'a' << 40 | (long)'r' << 32 | (long)'t' << 24 | (long)'s' << 16, 
188                         (long)'h' << 56 | (long)'e' << 48 | (long)'l' << 40 | (long)'l' << 32 | (long)'i' << 24 | (long)'p' << 16, 
189                         (long)'i' << 56 | (long)'a' << 48 | (long)'c' << 40 | (long)'u' << 32 | (long)'t' << 24 | (long)'e' << 16, 
190                         (long)'i' << 56 | (long)'c' << 48 | (long)'i' << 40 | (long)'r' << 32 | (long)'c' << 24, 
191                         (long)'i' << 56 | (long)'e' << 48 | (long)'x' << 40 | (long)'c' << 32 | (long)'l' << 24, 
192                         (long)'i' << 56 | (long)'g' << 48 | (long)'r' << 40 | (long)'a' << 32 | (long)'v' << 24 | (long)'e' << 16, 
193                         (long)'i' << 56 | (long)'m' << 48 | (long)'a' << 40 | (long)'g' << 32 | (long)'e' << 24, 
194                         (long)'i' << 56 | (long)'n' << 48 | (long)'f' << 40 | (long)'i' << 32 | (long)'n' << 24, 
195                         (long)'i' << 56 | (long)'n' << 48 | (long)'t' << 40, 
196                         (long)'i' << 56 | (long)'o' << 48 | (long)'t' << 40 | (long)'a' << 32, 
197                         (long)'i' << 56 | (long)'q' << 48 | (long)'u' << 40 | (long)'e' << 32 | (long)'s' << 24 | (long)'t' << 16, 
198                         (long)'i' << 56 | (long)'s' << 48 | (long)'i' << 40 | (long)'n' << 32, 
199                         (long)'i' << 56 | (long)'u' << 48 | (long)'m' << 40 | (long)'l' << 32, 
200                         (long)'k' << 56 | (long)'a' << 48 | (long)'p' << 40 | (long)'p' << 32 | (long)'a' << 24, 
201                         (long)'l' << 56 | (long)'A' << 48 | (long)'r' << 40 | (long)'r' << 32, 
202                         (long)'l' << 56 | (long)'a' << 48 | (long)'m' << 40 | (long)'b' << 32 | (long)'d' << 24 | (long)'a' << 16, 
203                         (long)'l' << 56 | (long)'a' << 48 | (long)'n' << 40 | (long)'g' << 32, 
204                         (long)'l' << 56 | (long)'a' << 48 | (long)'q' << 40 | (long)'u' << 32 | (long)'o' << 24, 
205                         (long)'l' << 56 | (long)'a' << 48 | (long)'r' << 40 | (long)'r' << 32, 
206                         (long)'l' << 56 | (long)'c' << 48 | (long)'e' << 40 | (long)'i' << 32 | (long)'l' << 24, 
207                         (long)'l' << 56 | (long)'d' << 48 | (long)'q' << 40 | (long)'u' << 32 | (long)'o' << 24, 
208                         (long)'l' << 56 | (long)'e' << 48, 
209                         (long)'l' << 56 | (long)'f' << 48 | (long)'l' << 40 | (long)'o' << 32 | (long)'o' << 24 | (long)'r' << 16, 
210                         (long)'l' << 56 | (long)'o' << 48 | (long)'w' << 40 | (long)'a' << 32 | (long)'s' << 24 | (long)'t' << 16, 
211                         (long)'l' << 56 | (long)'o' << 48 | (long)'z' << 40, 
212                         (long)'l' << 56 | (long)'r' << 48 | (long)'m' << 40, 
213                         (long)'l' << 56 | (long)'s' << 48 | (long)'a' << 40 | (long)'q' << 32 | (long)'u' << 24 | (long)'o' << 16, 
214                         (long)'l' << 56 | (long)'s' << 48 | (long)'q' << 40 | (long)'u' << 32 | (long)'o' << 24, 
215                         (long)'l' << 56 | (long)'t' << 48, 
216                         (long)'m' << 56 | (long)'a' << 48 | (long)'c' << 40 | (long)'r' << 32, 
217                         (long)'m' << 56 | (long)'d' << 48 | (long)'a' << 40 | (long)'s' << 32 | (long)'h' << 24, 
218                         (long)'m' << 56 | (long)'i' << 48 | (long)'c' << 40 | (long)'r' << 32 | (long)'o' << 24, 
219                         (long)'m' << 56 | (long)'i' << 48 | (long)'d' << 40 | (long)'d' << 32 | (long)'o' << 24 | (long)'t' << 16, 
220                         (long)'m' << 56 | (long)'i' << 48 | (long)'n' << 40 | (long)'u' << 32 | (long)'s' << 24, 
221                         (long)'m' << 56 | (long)'u' << 48, 
222                         (long)'n' << 56 | (long)'a' << 48 | (long)'b' << 40 | (long)'l' << 32 | (long)'a' << 24, 
223                         (long)'n' << 56 | (long)'b' << 48 | (long)'s' << 40 | (long)'p' << 32, 
224                         (long)'n' << 56 | (long)'d' << 48 | (long)'a' << 40 | (long)'s' << 32 | (long)'h' << 24, 
225                         (long)'n' << 56 | (long)'e' << 48, 
226                         (long)'n' << 56 | (long)'i' << 48, 
227                         (long)'n' << 56 | (long)'o' << 48 | (long)'t' << 40, 
228                         (long)'n' << 56 | (long)'o' << 48 | (long)'t' << 40 | (long)'i' << 32 | (long)'n' << 24, 
229                         (long)'n' << 56 | (long)'s' << 48 | (long)'u' << 40 | (long)'b' << 32, 
230                         (long)'n' << 56 | (long)'t' << 48 | (long)'i' << 40 | (long)'l' << 32 | (long)'d' << 24 | (long)'e' << 16, 
231                         (long)'n' << 56 | (long)'u' << 48, 
232                         (long)'o' << 56 | (long)'a' << 48 | (long)'c' << 40 | (long)'u' << 32 | (long)'t' << 24 | (long)'e' << 16, 
233                         (long)'o' << 56 | (long)'c' << 48 | (long)'i' << 40 | (long)'r' << 32 | (long)'c' << 24, 
234                         (long)'o' << 56 | (long)'e' << 48 | (long)'l' << 40 | (long)'i' << 32 | (long)'g' << 24, 
235                         (long)'o' << 56 | (long)'g' << 48 | (long)'r' << 40 | (long)'a' << 32 | (long)'v' << 24 | (long)'e' << 16, 
236                         (long)'o' << 56 | (long)'l' << 48 | (long)'i' << 40 | (long)'n' << 32 | (long)'e' << 24, 
237                         (long)'o' << 56 | (long)'m' << 48 | (long)'e' << 40 | (long)'g' << 32 | (long)'a' << 24, 
238                         (long)'o' << 56 | (long)'m' << 48 | (long)'i' << 40 | (long)'c' << 32 | (long)'r' << 24 | (long)'o' << 16 | (long)'n' << 8, 
239                         (long)'o' << 56 | (long)'p' << 48 | (long)'l' << 40 | (long)'u' << 32 | (long)'s' << 24, 
240                         (long)'o' << 56 | (long)'r' << 48, 
241                         (long)'o' << 56 | (long)'r' << 48 | (long)'d' << 40 | (long)'f' << 32, 
242                         (long)'o' << 56 | (long)'r' << 48 | (long)'d' << 40 | (long)'m' << 32, 
243                         (long)'o' << 56 | (long)'s' << 48 | (long)'l' << 40 | (long)'a' << 32 | (long)'s' << 24 | (long)'h' << 16, 
244                         (long)'o' << 56 | (long)'t' << 48 | (long)'i' << 40 | (long)'l' << 32 | (long)'d' << 24 | (long)'e' << 16, 
245                         (long)'o' << 56 | (long)'t' << 48 | (long)'i' << 40 | (long)'m' << 32 | (long)'e' << 24 | (long)'s' << 16, 
246                         (long)'o' << 56 | (long)'u' << 48 | (long)'m' << 40 | (long)'l' << 32, 
247                         (long)'p' << 56 | (long)'a' << 48 | (long)'r' << 40 | (long)'a' << 32, 
248                         (long)'p' << 56 | (long)'a' << 48 | (long)'r' << 40 | (long)'t' << 32, 
249                         (long)'p' << 56 | (long)'e' << 48 | (long)'r' << 40 | (long)'m' << 32 | (long)'i' << 24 | (long)'l' << 16, 
250                         (long)'p' << 56 | (long)'e' << 48 | (long)'r' << 40 | (long)'p' << 32, 
251                         (long)'p' << 56 | (long)'h' << 48 | (long)'i' << 40, 
252                         (long)'p' << 56 | (long)'i' << 48, 
253                         (long)'p' << 56 | (long)'i' << 48 | (long)'v' << 40, 
254                         (long)'p' << 56 | (long)'l' << 48 | (long)'u' << 40 | (long)'s' << 32 | (long)'m' << 24 | (long)'n' << 16, 
255                         (long)'p' << 56 | (long)'o' << 48 | (long)'u' << 40 | (long)'n' << 32 | (long)'d' << 24, 
256                         (long)'p' << 56 | (long)'r' << 48 | (long)'i' << 40 | (long)'m' << 32 | (long)'e' << 24, 
257                         (long)'p' << 56 | (long)'r' << 48 | (long)'o' << 40 | (long)'d' << 32, 
258                         (long)'p' << 56 | (long)'r' << 48 | (long)'o' << 40 | (long)'p' << 32, 
259                         (long)'p' << 56 | (long)'s' << 48 | (long)'i' << 40, 
260                         (long)'q' << 56 | (long)'u' << 48 | (long)'o' << 40 | (long)'t' << 32, 
261                         (long)'r' << 56 | (long)'A' << 48 | (long)'r' << 40 | (long)'r' << 32, 
262                         (long)'r' << 56 | (long)'a' << 48 | (long)'d' << 40 | (long)'i' << 32 | (long)'c' << 24, 
263                         (long)'r' << 56 | (long)'a' << 48 | (long)'n' << 40 | (long)'g' << 32, 
264                         (long)'r' << 56 | (long)'a' << 48 | (long)'q' << 40 | (long)'u' << 32 | (long)'o' << 24, 
265                         (long)'r' << 56 | (long)'a' << 48 | (long)'r' << 40 | (long)'r' << 32, 
266                         (long)'r' << 56 | (long)'c' << 48 | (long)'e' << 40 | (long)'i' << 32 | (long)'l' << 24, 
267                         (long)'r' << 56 | (long)'d' << 48 | (long)'q' << 40 | (long)'u' << 32 | (long)'o' << 24, 
268                         (long)'r' << 56 | (long)'e' << 48 | (long)'a' << 40 | (long)'l' << 32, 
269                         (long)'r' << 56 | (long)'e' << 48 | (long)'g' << 40, 
270                         (long)'r' << 56 | (long)'f' << 48 | (long)'l' << 40 | (long)'o' << 32 | (long)'o' << 24 | (long)'r' << 16, 
271                         (long)'r' << 56 | (long)'h' << 48 | (long)'o' << 40, 
272                         (long)'r' << 56 | (long)'l' << 48 | (long)'m' << 40, 
273                         (long)'r' << 56 | (long)'s' << 48 | (long)'a' << 40 | (long)'q' << 32 | (long)'u' << 24 | (long)'o' << 16, 
274                         (long)'r' << 56 | (long)'s' << 48 | (long)'q' << 40 | (long)'u' << 32 | (long)'o' << 24, 
275                         (long)'s' << 56 | (long)'b' << 48 | (long)'q' << 40 | (long)'u' << 32 | (long)'o' << 24, 
276                         (long)'s' << 56 | (long)'c' << 48 | (long)'a' << 40 | (long)'r' << 32 | (long)'o' << 24 | (long)'n' << 16, 
277                         (long)'s' << 56 | (long)'d' << 48 | (long)'o' << 40 | (long)'t' << 32, 
278                         (long)'s' << 56 | (long)'e' << 48 | (long)'c' << 40 | (long)'t' << 32, 
279                         (long)'s' << 56 | (long)'h' << 48 | (long)'y' << 40, 
280                         (long)'s' << 56 | (long)'i' << 48 | (long)'g' << 40 | (long)'m' << 32 | (long)'a' << 24, 
281                         (long)'s' << 56 | (long)'i' << 48 | (long)'g' << 40 | (long)'m' << 32 | (long)'a' << 24 | (long)'f' << 16, 
282                         (long)'s' << 56 | (long)'i' << 48 | (long)'m' << 40, 
283                         (long)'s' << 56 | (long)'p' << 48 | (long)'a' << 40 | (long)'d' << 32 | (long)'e' << 24 | (long)'s' << 16, 
284                         (long)'s' << 56 | (long)'u' << 48 | (long)'b' << 40, 
285                         (long)'s' << 56 | (long)'u' << 48 | (long)'b' << 40 | (long)'e' << 32, 
286                         (long)'s' << 56 | (long)'u' << 48 | (long)'m' << 40, 
287                         (long)'s' << 56 | (long)'u' << 48 | (long)'p' << 40, 
288                         (long)'s' << 56 | (long)'u' << 48 | (long)'p' << 40 | (long)'1' << 32, 
289                         (long)'s' << 56 | (long)'u' << 48 | (long)'p' << 40 | (long)'2' << 32, 
290                         (long)'s' << 56 | (long)'u' << 48 | (long)'p' << 40 | (long)'3' << 32, 
291                         (long)'s' << 56 | (long)'u' << 48 | (long)'p' << 40 | (long)'e' << 32, 
292                         (long)'s' << 56 | (long)'z' << 48 | (long)'l' << 40 | (long)'i' << 32 | (long)'g' << 24, 
293                         (long)'t' << 56 | (long)'a' << 48 | (long)'u' << 40, 
294                         (long)'t' << 56 | (long)'h' << 48 | (long)'e' << 40 | (long)'r' << 32 | (long)'e' << 24 | (long)'4' << 16, 
295                         (long)'t' << 56 | (long)'h' << 48 | (long)'e' << 40 | (long)'t' << 32 | (long)'a' << 24, 
296                         (long)'t' << 56 | (long)'h' << 48 | (long)'e' << 40 | (long)'t' << 32 | (long)'a' << 24 | (long)'s' << 16 | (long)'y' << 8 | (long)'m' << 0, 
297                         (long)'t' << 56 | (long)'h' << 48 | (long)'i' << 40 | (long)'n' << 32 | (long)'s' << 24 | (long)'p' << 16, 
298                         (long)'t' << 56 | (long)'h' << 48 | (long)'o' << 40 | (long)'r' << 32 | (long)'n' << 24, 
299                         (long)'t' << 56 | (long)'i' << 48 | (long)'l' << 40 | (long)'d' << 32 | (long)'e' << 24, 
300                         (long)'t' << 56 | (long)'i' << 48 | (long)'m' << 40 | (long)'e' << 32 | (long)'s' << 24, 
301                         (long)'t' << 56 | (long)'r' << 48 | (long)'a' << 40 | (long)'d' << 32 | (long)'e' << 24, 
302                         (long)'u' << 56 | (long)'A' << 48 | (long)'r' << 40 | (long)'r' << 32, 
303                         (long)'u' << 56 | (long)'a' << 48 | (long)'c' << 40 | (long)'u' << 32 | (long)'t' << 24 | (long)'e' << 16, 
304                         (long)'u' << 56 | (long)'a' << 48 | (long)'r' << 40 | (long)'r' << 32, 
305                         (long)'u' << 56 | (long)'c' << 48 | (long)'i' << 40 | (long)'r' << 32 | (long)'c' << 24, 
306                         (long)'u' << 56 | (long)'g' << 48 | (long)'r' << 40 | (long)'a' << 32 | (long)'v' << 24 | (long)'e' << 16, 
307                         (long)'u' << 56 | (long)'m' << 48 | (long)'l' << 40, 
308                         (long)'u' << 56 | (long)'p' << 48 | (long)'s' << 40 | (long)'i' << 32 | (long)'h' << 24, 
309                         (long)'u' << 56 | (long)'p' << 48 | (long)'s' << 40 | (long)'i' << 32 | (long)'l' << 24 | (long)'o' << 16 | (long)'n' << 8, 
310                         (long)'u' << 56 | (long)'u' << 48 | (long)'m' << 40 | (long)'l' << 32, 
311                         (long)'w' << 56 | (long)'e' << 48 | (long)'i' << 40 | (long)'e' << 32 | (long)'r' << 24 | (long)'p' << 16, 
312                         (long)'x' << 56 | (long)'i' << 48, 
313                         (long)'y' << 56 | (long)'a' << 48 | (long)'c' << 40 | (long)'u' << 32 | (long)'t' << 24 | (long)'e' << 16, 
314                         (long)'y' << 56 | (long)'e' << 48 | (long)'n' << 40, 
315                         (long)'y' << 56 | (long)'u' << 48 | (long)'m' << 40 | (long)'l' << 32, 
316                         (long)'z' << 56 | (long)'e' << 48 | (long)'t' << 40 | (long)'a' << 32, 
317                         (long)'z' << 56 | (long)'w' << 48 | (long)'j' << 40, 
318                         (long)'z' << 56 | (long)'w' << 48 | (long)'n' << 40 | (long)'j' << 32
319                 };
320
321                 static readonly char[] entities_values = new char[] {
322                         '\u00C6',
323                         '\u00C1',
324                         '\u00C2',
325                         '\u00C0',
326                         '\u0391',
327                         '\u00C5',
328                         '\u00C3',
329                         '\u00C4',
330                         '\u0392',
331                         '\u00C7',
332                         '\u03A7',
333                         '\u2021',
334                         '\u0394',
335                         '\u00D0',
336                         '\u00C9',
337                         '\u00CA',
338                         '\u00C8',
339                         '\u0395',
340                         '\u0397',
341                         '\u00CB',
342                         '\u0393',
343                         '\u00CD',
344                         '\u00CE',
345                         '\u00CC',
346                         '\u0399',
347                         '\u00CF',
348                         '\u039A',
349                         '\u039B',
350                         '\u039C',
351                         '\u00D1',
352                         '\u039D',
353                         '\u0152',
354                         '\u00D3',
355                         '\u00D4',
356                         '\u00D2',
357                         '\u03A9',
358                         '\u039F',
359                         '\u00D8',
360                         '\u00D5',
361                         '\u00D6',
362                         '\u03A6',
363                         '\u03A0',
364                         '\u2033',
365                         '\u03A8',
366                         '\u03A1',
367                         '\u0160',
368                         '\u03A3',
369                         '\u00DE',
370                         '\u03A4',
371                         '\u0398',
372                         '\u00DA',
373                         '\u00DB',
374                         '\u00D9',
375                         '\u03A5',
376                         '\u00DC',
377                         '\u039E',
378                         '\u00DD',
379                         '\u0178',
380                         '\u0396',
381                         '\u00E1',
382                         '\u00E2',
383                         '\u00B4',
384                         '\u00E6',
385                         '\u00E0',
386                         '\u2135',
387                         '\u03B1',
388                         '\u0026',
389                         '\u2227',
390                         '\u2220',
391                         '\u0027',
392                         '\u00E5',
393                         '\u2248',
394                         '\u00E3',
395                         '\u00E4',
396                         '\u201E',
397                         '\u03B2',
398                         '\u00A6',
399                         '\u2022',
400                         '\u2229',
401                         '\u00E7',
402                         '\u00B8',
403                         '\u00A2',
404                         '\u03C7',
405                         '\u02C6',
406                         '\u2663',
407                         '\u2245',
408                         '\u00A9',
409                         '\u21B5',
410                         '\u222A',
411                         '\u00A4',
412                         '\u21D3',
413                         '\u2020',
414                         '\u2193',
415                         '\u00B0',
416                         '\u03B4',
417                         '\u2666',
418                         '\u00F7',
419                         '\u00E9',
420                         '\u00EA',
421                         '\u00E8',
422                         '\u2205',
423                         '\u2003',
424                         '\u2002',
425                         '\u03B5',
426                         '\u2261',
427                         '\u03B7',
428                         '\u00F0',
429                         '\u00EB',
430                         '\u20AC',
431                         '\u2203',
432                         '\u0192',
433                         '\u2200',
434                         '\u00BD',
435                         '\u00BC',
436                         '\u00BE',
437                         '\u2044',
438                         '\u03B3',
439                         '\u2265',
440                         '\u003E',
441                         '\u21D4',
442                         '\u2194',
443                         '\u2665',
444                         '\u2026',
445                         '\u00ED',
446                         '\u00EE',
447                         '\u00A1',
448                         '\u00EC',
449                         '\u2111',
450                         '\u221E',
451                         '\u222B',
452                         '\u03B9',
453                         '\u00BF',
454                         '\u2208',
455                         '\u00EF',
456                         '\u03BA',
457                         '\u21D0',
458                         '\u03BB',
459                         '\u2329',
460                         '\u00AB',
461                         '\u2190',
462                         '\u2308',
463                         '\u201C',
464                         '\u2264',
465                         '\u230A',
466                         '\u2217',
467                         '\u25CA',
468                         '\u200E',
469                         '\u2039',
470                         '\u2018',
471                         '\u003C',
472                         '\u00AF',
473                         '\u2014',
474                         '\u00B5',
475                         '\u00B7',
476                         '\u2212',
477                         '\u03BC',
478                         '\u2207',
479                         '\u00A0',
480                         '\u2013',
481                         '\u2260',
482                         '\u220B',
483                         '\u00AC',
484                         '\u2209',
485                         '\u2284',
486                         '\u00F1',
487                         '\u03BD',
488                         '\u00F3',
489                         '\u00F4',
490                         '\u0153',
491                         '\u00F2',
492                         '\u203E',
493                         '\u03C9',
494                         '\u03BF',
495                         '\u2295',
496                         '\u2228',
497                         '\u00AA',
498                         '\u00BA',
499                         '\u00F8',
500                         '\u00F5',
501                         '\u2297',
502                         '\u00F6',
503                         '\u00B6',
504                         '\u2202',
505                         '\u2030',
506                         '\u22A5',
507                         '\u03C6',
508                         '\u03C0',
509                         '\u03D6',
510                         '\u00B1',
511                         '\u00A3',
512                         '\u2032',
513                         '\u220F',
514                         '\u221D',
515                         '\u03C8',
516                         '\u0022',
517                         '\u21D2',
518                         '\u221A',
519                         '\u232A',
520                         '\u00BB',
521                         '\u2192',
522                         '\u2309',
523                         '\u201D',
524                         '\u211C',
525                         '\u00AE',
526                         '\u230B',
527                         '\u03C1',
528                         '\u200F',
529                         '\u203A',
530                         '\u2019',
531                         '\u201A',
532                         '\u0161',
533                         '\u22C5',
534                         '\u00A7',
535                         '\u00AD',
536                         '\u03C3',
537                         '\u03C2',
538                         '\u223C',
539                         '\u2660',
540                         '\u2282',
541                         '\u2286',
542                         '\u2211',
543                         '\u2283',
544                         '\u00B9',
545                         '\u00B2',
546                         '\u00B3',
547                         '\u2287',
548                         '\u00DF',
549                         '\u03C4',
550                         '\u2234',
551                         '\u03B8',
552                         '\u03D1',
553                         '\u2009',
554                         '\u00FE',
555                         '\u02DC',
556                         '\u00D7',
557                         '\u2122',
558                         '\u21D1',
559                         '\u00FA',
560                         '\u2191',
561                         '\u00FB',
562                         '\u00F9',
563                         '\u00A8',
564                         '\u03D2',
565                         '\u03C5',
566                         '\u00FC',
567                         '\u2118',
568                         '\u03BE',
569                         '\u00FD',
570                         '\u00A5',
571                         '\u00FF',
572                         '\u03B6',
573                         '\u200D',
574                         '\u200C'
575                 };
576
577                 static readonly char[] hexChars = new [] {
578                         '0',
579                         '1',
580                         '2',
581                         '3',
582                         '4',
583                         '5',
584                         '6',
585                         '7',
586                         '8',
587                         '9',
588                         'A',
589                         'B',
590                         'C',
591                         'D',
592                         'E',
593                         'F'
594                 };
595
596                 #region Methods
597         
598                 public static void HtmlAttributeEncode (string s, TextWriter output) 
599                 {
600                         output.Write(HtmlAttributeEncode(s));
601                 }
602         
603                 public static string HtmlAttributeEncode (string s) 
604                 {
605                         if (null == s) 
606                                 return null;
607         
608                         bool needEncode = false;
609                         for (int i = 0; i < s.Length; i++) {
610                                 if (s [i] == '&' || s [i] == '"' || s [i] == '<') {
611                                         needEncode = true;
612                                         break;
613                                 }
614                         }
615
616                         if (!needEncode)
617                                 return s;
618
619                         StringBuilder output = new StringBuilder ();
620                         int len = s.Length;
621                         for (int i = 0; i < len; i++)
622                                 switch (s [i]) {
623                                 case '&' : 
624                                         output.Append ("&amp;");
625                                         break;
626                                 case '"' :
627                                         output.Append ("&quot;");
628                                         break;
629                                 case '<':
630                                         output.Append ("&lt;");
631                                         break;
632                                 default:
633                                         output.Append (s [i]);
634                                         break;
635                                 }
636         
637                         return output.ToString();
638                 }
639         
640                 public static string UrlDecode (string str) 
641                 {
642                         return UrlDecode(str, Encoding.UTF8);
643                 }
644         
645                 static char [] GetChars (MemoryStream b, Encoding e)
646                 {
647                         return e.GetChars (b.GetBuffer (), 0, (int) b.Length);
648                 }
649
650                 static void WriteCharBytes (IList buf, char ch, Encoding e)
651                 {
652                         if (ch > 255) {
653                                 foreach (byte b in e.GetBytes (new char[] { ch }))
654                                         buf.Add (b);
655                         } else
656                                 buf.Add ((byte)ch);
657                 }
658                 
659                 public static string UrlDecode (string s, Encoding e)
660                 {
661                         if (null == s) 
662                                 return null;
663
664                         if (s.IndexOf ('%') == -1 && s.IndexOf ('+') == -1)
665                                 return s;
666                         
667                         if (e == null)
668                                 e = Encoding.UTF8;
669
670                         long len = s.Length;
671                         var bytes = new List <byte> ();
672                         int xchar;
673                         char ch;
674                         
675                         for (int i = 0; i < len; i++) {
676                                 ch = s [i];
677                                 if (ch == '%' && i + 2 < len && s [i + 1] != '%') {
678                                         if (s [i + 1] == 'u' && i + 5 < len) {
679                                                 // unicode hex sequence
680                                                 xchar = GetChar (s, i + 2, 4);
681                                                 if (xchar != -1) {
682                                                         WriteCharBytes (bytes, (char)xchar, e);
683                                                         i += 5;
684                                                 } else
685                                                         WriteCharBytes (bytes, '%', e);
686                                         } else if ((xchar = GetChar (s, i + 1, 2)) != -1) {
687                                                 WriteCharBytes (bytes, (char)xchar, e);
688                                                 i += 2;
689                                         } else {
690                                                 WriteCharBytes (bytes, '%', e);
691                                         }
692                                         continue;
693                                 }
694
695                                 if (ch == '+')
696                                         WriteCharBytes (bytes, ' ', e);
697                                 else
698                                         WriteCharBytes (bytes, ch, e);
699                         }
700                         
701                         byte[] buf = bytes.ToArray ();
702                         bytes = null;
703                         return e.GetString (buf);
704                         
705                 }
706         
707                 public static string UrlDecode (byte [] bytes, Encoding e)
708                 {
709                         if (bytes == null)
710                                 return null;
711
712                         return UrlDecode (bytes, 0, bytes.Length, e);
713                 }
714
715                 static int GetInt (byte b)
716                 {
717                         char c = (char) b;
718                         if (c >= '0' && c <= '9')
719                                 return c - '0';
720
721                         if (c >= 'a' && c <= 'f')
722                                 return c - 'a' + 10;
723
724                         if (c >= 'A' && c <= 'F')
725                                 return c - 'A' + 10;
726
727                         return -1;
728                 }
729
730                 static int GetChar (byte [] bytes, int offset, int length)
731                 {
732                         int value = 0;
733                         int end = length + offset;
734                         for (int i = offset; i < end; i++) {
735                                 int current = GetInt (bytes [i]);
736                                 if (current == -1)
737                                         return -1;
738                                 value = (value << 4) + current;
739                         }
740
741                         return value;
742                 }
743
744                 static int GetChar (string str, int offset, int length)
745                 {
746                         int val = 0;
747                         int end = length + offset;
748                         for (int i = offset; i < end; i++) {
749                                 char c = str [i];
750                                 if (c > 127)
751                                         return -1;
752
753                                 int current = GetInt ((byte) c);
754                                 if (current == -1)
755                                         return -1;
756                                 val = (val << 4) + current;
757                         }
758
759                         return val;
760                 }
761                 
762                 public static string UrlDecode (byte [] bytes, int offset, int count, Encoding e)
763                 {
764                         if (bytes == null)
765                                 return null;
766                         if (count == 0)
767                                 return String.Empty;
768
769                         if (bytes == null)
770                                 throw new ArgumentNullException ("bytes");
771
772                         if (offset < 0 || offset > bytes.Length)
773                                 throw new ArgumentOutOfRangeException ("offset");
774
775                         if (count < 0 || offset + count > bytes.Length)
776                                 throw new ArgumentOutOfRangeException ("count");
777
778                         StringBuilder output = new StringBuilder ();
779                         MemoryStream acc = new MemoryStream ();
780
781                         int end = count + offset;
782                         int xchar;
783                         for (int i = offset; i < end; i++) {
784                                 if (bytes [i] == '%' && i + 2 < count && bytes [i + 1] != '%') {
785                                         if (bytes [i + 1] == (byte) 'u' && i + 5 < end) {
786                                                 if (acc.Length > 0) {
787                                                         output.Append (GetChars (acc, e));
788                                                         acc.SetLength (0);
789                                                 }
790                                                 xchar = GetChar (bytes, i + 2, 4);
791                                                 if (xchar != -1) {
792                                                         output.Append ((char) xchar);
793                                                         i += 5;
794                                                         continue;
795                                                 }
796                                         } else if ((xchar = GetChar (bytes, i + 1, 2)) != -1) {
797                                                 acc.WriteByte ((byte) xchar);
798                                                 i += 2;
799                                                 continue;
800                                         }
801                                 }
802
803                                 if (acc.Length > 0) {
804                                         output.Append (GetChars (acc, e));
805                                         acc.SetLength (0);
806                                 }
807
808                                 if (bytes [i] == '+') {
809                                         output.Append (' ');
810                                 } else {
811                                         output.Append ((char) bytes [i]);
812                                 }
813                         }
814
815                         if (acc.Length > 0) {
816                                 output.Append (GetChars (acc, e));
817                         }
818                         
819                         acc = null;
820                         return output.ToString ();
821                 }
822         
823                 public static byte [] UrlDecodeToBytes (byte [] bytes)
824                 {
825                         if (bytes == null)
826                                 return null;
827
828                         return UrlDecodeToBytes (bytes, 0, bytes.Length);
829                 }
830
831                 public static byte [] UrlDecodeToBytes (string str)
832                 {
833                         return UrlDecodeToBytes (str, Encoding.UTF8);
834                 }
835
836                 public static byte [] UrlDecodeToBytes (string str, Encoding e)
837                 {
838                         if (str == null)
839                                 return null;
840
841                         if (e == null)
842                                 throw new ArgumentNullException ("e");
843
844                         return UrlDecodeToBytes (e.GetBytes (str));
845                 }
846
847                 public static byte [] UrlDecodeToBytes (byte [] bytes, int offset, int count)
848                 {
849                         if (bytes == null)
850                                 return null;
851                         if (count == 0)
852                                 return new byte [0];
853
854                         int len = bytes.Length;
855                         if (offset < 0 || offset >= len)
856                                 throw new ArgumentOutOfRangeException("offset");
857
858                         if (count < 0 || offset > len - count)
859                                 throw new ArgumentOutOfRangeException("count");
860
861                         MemoryStream result = new MemoryStream ();
862                         int end = offset + count;
863                         for (int i = offset; i < end; i++){
864                                 char c = (char) bytes [i];
865                                 if (c == '+') {
866                                         c = ' ';
867                                 } else if (c == '%' && i < end - 2) {
868                                         int xchar = GetChar (bytes, i + 1, 2);
869                                         if (xchar != -1) {
870                                                 c = (char) xchar;
871                                                 i += 2;
872                                         }
873                                 }
874                                 result.WriteByte ((byte) c);
875                         }
876
877                         return result.ToArray ();
878                 }
879
880                 public static string UrlEncode(string str) 
881                 {
882                         return UrlEncode(str, Encoding.UTF8);
883                 }
884         
885                 public static string UrlEncode (string s, Encoding Enc) 
886                 {
887                         if (string.IsNullOrEmpty (s))
888                                 return s;
889
890                         bool needEncode = false;
891                         int len = s.Length;
892                         for (int i = 0; i < len; i++) {
893                                 char c = s [i];
894                                 if ((c < '0') || (c < 'A' && c > '9') || (c > 'Z' && c < 'a') || (c > 'z')) {
895                                         if (NotEncoded (c))
896                                                 continue;
897
898                                         needEncode = true;
899                                         break;
900                                 }
901                         }
902
903                         if (!needEncode)
904                                 return s;
905
906                         // avoided GetByteCount call
907                         byte [] bytes = new byte[Enc.GetMaxByteCount(s.Length)];
908                         int realLen = Enc.GetBytes (s, 0, s.Length, bytes, 0);
909                         return Encoding.ASCII.GetString (UrlEncodeToBytes (bytes, 0, realLen));
910                 }
911           
912                 public static string UrlEncode (byte [] bytes)
913                 {
914                         if (bytes == null)
915                                 return null;
916
917                         if (bytes.Length == 0)
918                                 return "";
919
920                         return Encoding.ASCII.GetString (UrlEncodeToBytes (bytes, 0, bytes.Length));
921                 }
922
923                 public static string UrlEncode (byte [] bytes, int offset, int count)
924                 {
925                         if (bytes == null)
926                                 return null;
927
928                         if (bytes.Length == 0)
929                                 return "";
930
931                         return Encoding.ASCII.GetString (UrlEncodeToBytes (bytes, offset, count));
932                 }
933
934                 public static byte [] UrlEncodeToBytes (string str)
935                 {
936                         return UrlEncodeToBytes (str, Encoding.UTF8);
937                 }
938
939                 public static byte [] UrlEncodeToBytes (string str, Encoding e)
940                 {
941                         if (str == null)
942                                 return null;
943
944                         if (str == "")
945                                 return new byte [0];
946
947                         byte [] bytes = e.GetBytes (str);
948                         return UrlEncodeToBytes (bytes, 0, bytes.Length);
949                 }
950
951                 public static byte [] UrlEncodeToBytes (byte [] bytes)
952                 {
953                         if (bytes == null)
954                                 return null;
955
956                         if (bytes.Length == 0)
957                                 return new byte [0];
958
959                         return UrlEncodeToBytes (bytes, 0, bytes.Length);
960                 }
961                         
962                 static bool NotEncoded (char c)
963                 {
964                         return (c == '!' || c == '(' || c == ')' || c == '*' || c == '-' || c == '.' || c == '_');
965                 }
966
967                 static void UrlEncodeChar (char c, Stream result, bool isUnicode) {
968                         if (c > 255) {
969                                 //FIXME: what happens when there is an internal error?
970                                 //if (!isUnicode)
971                                 //      throw new ArgumentOutOfRangeException ("c", c, "c must be less than 256");
972                                 int idx;
973                                 int i = (int) c;
974
975                                 result.WriteByte ((byte)'%');
976                                 result.WriteByte ((byte)'u');
977                                 idx = i >> 12;
978                                 result.WriteByte ((byte)hexChars [idx]);
979                                 idx = (i >> 8) & 0x0F;
980                                 result.WriteByte ((byte)hexChars [idx]);
981                                 idx = (i >> 4) & 0x0F;
982                                 result.WriteByte ((byte)hexChars [idx]);
983                                 idx = i & 0x0F;
984                                 result.WriteByte ((byte)hexChars [idx]);
985                                 return;
986                         }
987                         
988                         if (c > ' ' && NotEncoded (c)) {
989                                 result.WriteByte ((byte)c);
990                                 return;
991                         }
992                         if (c==' ') {
993                                 result.WriteByte ((byte)'+');
994                                 return;
995                         }
996                         if (    (c < '0') ||
997                                 (c < 'A' && c > '9') ||
998                                 (c > 'Z' && c < 'a') ||
999                                 (c > 'z')) {
1000                                 if (isUnicode && c > 127) {
1001                                         result.WriteByte ((byte)'%');
1002                                         result.WriteByte ((byte)'u');
1003                                         result.WriteByte ((byte)'0');
1004                                         result.WriteByte ((byte)'0');
1005                                 }
1006                                 else
1007                                         result.WriteByte ((byte)'%');
1008                                 
1009                                 int idx = ((int) c) >> 4;
1010                                 result.WriteByte ((byte)hexChars [idx]);
1011                                 idx = ((int) c) & 0x0F;
1012                                 result.WriteByte ((byte)hexChars [idx]);
1013                         }
1014                         else
1015                                 result.WriteByte ((byte)c);
1016                 }
1017
1018                 public static byte [] UrlEncodeToBytes (byte [] bytes, int offset, int count)
1019                 {
1020                         if (bytes == null)
1021                                 return null;
1022
1023                         int len = bytes.Length;
1024                         if (len == 0)
1025                                 return new byte [0];
1026
1027                         if (offset < 0 || offset >= len)
1028                                 throw new ArgumentOutOfRangeException("offset");
1029
1030                         if (count < 0 || count > len - offset)
1031                                 throw new ArgumentOutOfRangeException("count");
1032
1033                         MemoryStream result = new MemoryStream (count);
1034                         int end = offset + count;
1035                         for (int i = offset; i < end; i++)
1036                                 UrlEncodeChar ((char)bytes [i], result, false);
1037
1038                         return result.ToArray();
1039                 }
1040
1041                 public static string UrlEncodeUnicode (string str)
1042                 {
1043                         if (str == null)
1044                                 return null;
1045
1046                         return Encoding.ASCII.GetString (UrlEncodeUnicodeToBytes (str));
1047                 }
1048
1049                 public static byte [] UrlEncodeUnicodeToBytes (string str)
1050                 {
1051                         if (str == null)
1052                                 return null;
1053
1054                         if (str == "")
1055                                 return new byte [0];
1056
1057                         MemoryStream result = new MemoryStream (str.Length);
1058                         foreach (char c in str){
1059                                 UrlEncodeChar (c, result, true);
1060                         }
1061                         return result.ToArray ();
1062                 }
1063
1064                 static bool TryConvertKeyToEntity (string key, out char value)
1065                 {
1066                         var token = CalculateKeyValue (key);
1067                         if (token == 0) {
1068                                 value = '\0';
1069                                 return false;
1070                         }
1071
1072                         var idx = Array.BinarySearch (entities, token);
1073                         if (idx < 0) {
1074                                 value = '\0';
1075                                 return false;
1076                         }
1077
1078                         value = entities_values [idx];
1079                         return true;
1080                 }
1081
1082                 static long CalculateKeyValue (string s)
1083                 {
1084                         if (s.Length > 8)
1085                                 return 0;
1086
1087                         long key = 0;
1088                         for (int i = 0; i < s.Length; ++i) {
1089                                 long ch = s[i];
1090                                 if (ch > 'z' || ch < '0')
1091                                         return 0;
1092
1093                                 key |= ch << ((7 - i) * 8);
1094                         }
1095
1096                         return key;
1097                 }
1098
1099                 /// <summary>
1100                 /// Decodes an HTML-encoded string and returns the decoded string.
1101                 /// </summary>
1102                 /// <param name="s">The HTML string to decode. </param>
1103                 /// <returns>The decoded text.</returns>
1104                 public static string HtmlDecode (string s) 
1105                 {
1106                         if (s == null)
1107                                 throw new ArgumentNullException ("s");
1108
1109                         if (s.IndexOf ('&') == -1)
1110                                 return s;
1111
1112                         StringBuilder entity = new StringBuilder ();
1113                         StringBuilder output = new StringBuilder ();
1114                         int len = s.Length;
1115                         // 0 -> nothing,
1116                         // 1 -> right after '&'
1117                         // 2 -> between '&' and ';' but no '#'
1118                         // 3 -> '#' found after '&' and getting numbers
1119                         int state = 0;
1120                         int number = 0;
1121                         int digit_start = 0;
1122                         bool hex_number = false;
1123         
1124                         for (int i = 0; i < len; i++) {
1125                                 char c = s [i];
1126                                 if (state == 0) {
1127                                         if (c == '&') {
1128                                                 entity.Append (c);
1129                                                 state = 1;
1130                                         } else {
1131                                                 output.Append (c);
1132                                         }
1133                                         continue;
1134                                 }
1135
1136                                 if (c == '&') {
1137                                         state = 1;
1138                                         if (digit_start > 0) {
1139                                                 entity.Append (s, digit_start, i - digit_start);
1140                                                 digit_start = 0;
1141                                         }
1142
1143                                         output.Append (entity.ToString ());
1144                                         entity.Length = 0;
1145                                         entity.Append ('&');
1146                                         continue;
1147                                 }
1148
1149                                 switch (state) {
1150                                 case 1:
1151                                         if (c == ';') {
1152                                                 state = 0;
1153                                                 output.Append (entity.ToString ());
1154                                                 output.Append (c);
1155                                                 entity.Length = 0;
1156                                                 break;
1157                                         }
1158
1159                                         number = 0;
1160                                         hex_number = false;
1161                                         if (c != '#') {
1162                                                 state = 2;
1163                                         } else {
1164                                                 state = 3;
1165                                         }
1166                                         entity.Append (c);
1167
1168                                         break;
1169                                 case 2:
1170                                         entity.Append (c);
1171                                         if (c == ';') {
1172                                                 string key = entity.ToString ();
1173                                                 state = 0;
1174                                                 entity.Length = 0;
1175
1176                                                 if (key.Length > 1) {
1177                                                         var skey = key.Substring (1, key.Length - 2);
1178                                                         if (TryConvertKeyToEntity (skey, out c)) {
1179                                                                 output.Append (c);
1180                                                                 break;
1181                                                         }
1182                                                 }
1183
1184                                                 output.Append (key);
1185                                         }
1186
1187                                         break;
1188                                 case 3:
1189                                         if (c == ';') {
1190                                                 if (number < 0x10000) {
1191                                                         output.Append ((char)number);
1192                                                 } else {
1193                                                         output.Append ((char)(0xd800 + ((number - 0x10000) >> 10)));
1194                                                         output.Append ((char)(0xdc00 + ((number - 0x10000) & 0x3ff)));
1195                                                 }
1196                                                 state = 0;
1197                                                 entity.Length = 0;
1198                                                 digit_start = 0;
1199                                                 break;
1200                                         }
1201
1202                                         if (c == 'x' || c == 'X' && !hex_number) {
1203                                                 digit_start = i;
1204                                                 hex_number = true;
1205                                                 break;
1206                                         }
1207
1208                                         if (Char.IsDigit (c)) {
1209                                                 if (digit_start == 0)
1210                                                         digit_start = i;
1211
1212                                                 number = number * (hex_number ? 16 : 10) + ((int)c - '0');
1213                                                 break;
1214                                         }
1215
1216                                         if (hex_number) {
1217                                                 if (c >= 'a' && c <= 'f') {
1218                                                         number = number * 16 + 10 + ((int)c - 'a');
1219                                                         break;
1220                                                 }
1221                                                 if (c >= 'A' && c <= 'F') {
1222                                                         number = number * 16 + 10 + ((int)c - 'A');
1223                                                         break;
1224                                                 }
1225                                         }
1226
1227                                         state = 2;
1228                                         if (digit_start > 0) {
1229                                                 entity.Append (s, digit_start, i - digit_start);
1230                                                 digit_start = 0;
1231                                         }
1232
1233                                         entity.Append (c);
1234                                         break;
1235                                 }
1236                         }
1237
1238                         if (entity.Length > 0) {
1239                                 output.Append (entity);
1240                         } else if (digit_start > 0) {
1241                                 output.Append (s, digit_start, s.Length - digit_start);
1242                         }
1243                         return output.ToString ();
1244                 }
1245         
1246                 /// <summary>
1247                 /// Decodes an HTML-encoded string and sends the resulting output to a TextWriter output stream.
1248                 /// </summary>
1249                 /// <param name="s">The HTML string to decode</param>
1250                 /// <param name="output">The TextWriter output stream containing the decoded string. </param>
1251                 public static void HtmlDecode(string s, TextWriter output) 
1252                 {
1253                         if (s != null)
1254                                 output.Write (HtmlDecode (s));
1255                 }
1256         
1257                 /// <summary>
1258                 /// HTML-encodes a string and returns the encoded string.
1259                 /// </summary>
1260                 /// <param name="s">The text string to encode. </param>
1261                 /// <returns>The HTML-encoded text.</returns>
1262                 public static string HtmlEncode (string s) 
1263                 {
1264                         if (s == null)
1265                                 return null;
1266
1267                         bool needEncode = false;
1268                         int i;
1269                         for (i = 0; i < s.Length; i++) {
1270                                 char c = s [i];
1271                                 switch (c) {
1272                                 case '&':
1273                                 case '"':
1274                                 case '<':
1275                                 case '>':
1276                                 case '\'':
1277                                         needEncode = true;
1278                                         break;
1279                                 default:
1280                                         if (c > 159) {
1281                                                 needEncode = true;
1282                                                 break;
1283                                         }
1284
1285                                         continue;
1286                                 }
1287
1288                                 break;
1289                         }
1290
1291                         if (!needEncode)
1292                                 return s;
1293
1294                         StringBuilder output = new StringBuilder (s, 0, i, s.Length * 2);
1295                         
1296                         for (; i < s.Length; i++) {
1297                                 var c = s [i];
1298                                 switch (c) {
1299                                 case '&' :
1300                                         output.Append ("&amp;");
1301                                         break;
1302                                 case '>' : 
1303                                         output.Append ("&gt;");
1304                                         break;
1305                                 case '<' :
1306                                         output.Append ("&lt;");
1307                                         break;
1308                                 case '"' :
1309                                         output.Append ("&quot;");
1310                                         break;
1311                                 case '\'':
1312                                         output.Append ("&#39;");
1313                                         break;
1314                                 default:
1315                                         // MS starts encoding with &# from 160 and stops at 255.
1316                                         // We don't do that. One reason is the 65308/65310 unicode
1317                                         // characters that look like '<' and '>'.
1318 #if TARGET_JVM
1319                                         if (c > 159 && c < 256) {
1320 #else
1321                                         if (c > 159) {
1322 #endif
1323                                                 output.Append ("&#");
1324                                                 if (char.IsSurrogate (c))
1325                                                         output.Append (char.ConvertToUtf32 (s, i++));
1326                                                 else
1327                                                         output.Append (((int) c).ToString (CultureInfo.InvariantCulture));
1328
1329                                                 output.Append (";");
1330                                         } else {
1331                                                 output.Append (c);
1332                                         }
1333                                         break;
1334                                 }
1335                         }
1336
1337                         return output.ToString ();
1338                 }
1339         
1340                 /// <summary>
1341                 /// HTML-encodes a string and sends the resulting output to a TextWriter output stream.
1342                 /// </summary>
1343                 /// <param name="s">The string to encode. </param>
1344                 /// <param name="output">The TextWriter output stream containing the encoded string. </param>
1345                 public static void HtmlEncode(string s, TextWriter output) 
1346                 {
1347                         if (s != null)
1348                                 output.Write (HtmlEncode (s));
1349                 }
1350
1351                 public static string UrlPathEncode (string s)
1352                 {
1353                         if (s == null || s.Length == 0)
1354                                 return s;
1355
1356                         MemoryStream result = new MemoryStream ();
1357                         int length = s.Length;
1358                         for (int i = 0; i < length; i++) {
1359                                 UrlPathEncodeChar (s [i], result);
1360                         }
1361                         return Encoding.ASCII.GetString (result.ToArray ());
1362                 }
1363                 
1364                 static void UrlPathEncodeChar (char c, Stream result)
1365                 {
1366                         if (c < 33 || c > 126) {
1367                                 byte [] bIn = Encoding.UTF8.GetBytes (c.ToString ());
1368                                 for (int i = 0; i < bIn.Length; i++) {
1369                                         result.WriteByte ((byte) '%');
1370                                         int idx = ((int) bIn [i]) >> 4;
1371                                         result.WriteByte ((byte) hexChars [idx]);
1372                                         idx = ((int) bIn [i]) & 0x0F;
1373                                         result.WriteByte ((byte) hexChars [idx]);
1374                                 }
1375                         }
1376                         else if (c == ' ') {
1377                                 result.WriteByte ((byte) '%');
1378                                 result.WriteByte ((byte) '2');
1379                                 result.WriteByte ((byte) '0');
1380                         }
1381                         else
1382                                 result.WriteByte ((byte) c);
1383                 }
1384
1385                 public static NameValueCollection ParseQueryString (string query)
1386                 {
1387                         return ParseQueryString (query, Encoding.UTF8);
1388                 }
1389
1390                 public static NameValueCollection ParseQueryString (string query, Encoding encoding)
1391                 {
1392                         if (query == null)
1393                                 throw new ArgumentNullException ("query");
1394                         if (encoding == null)
1395                                 throw new ArgumentNullException ("encoding");
1396                         if (query.Length == 0 || (query.Length == 1 && query[0] == '?'))
1397                                 return new NameValueCollection ();
1398                         if (query[0] == '?')
1399                                 query = query.Substring (1);
1400                                 
1401                         NameValueCollection result = new HttpQSCollection ();
1402                         ParseQueryString (query, encoding, result);
1403                         return result;
1404                 }
1405
1406                 internal static void ParseQueryString (string query, Encoding encoding, NameValueCollection result)
1407                 {
1408                         if (query.Length == 0)
1409                                 return;
1410
1411                         string decoded = HtmlDecode (query);
1412                         int decodedLength = decoded.Length;
1413                         int namePos = 0;
1414                         bool first = true;
1415                         while (namePos <= decodedLength) {
1416                                 int valuePos = -1, valueEnd = -1;
1417                                 for (int q = namePos; q < decodedLength; q++) {
1418                                         if (valuePos == -1 && decoded [q] == '=') {
1419                                                 valuePos = q + 1;
1420                                         } else if (decoded [q] == '&') {
1421                                                 valueEnd = q;
1422                                                 break;
1423                                         }
1424                                 }
1425
1426                                 if (first) {
1427                                         first = false;
1428                                         if (decoded [namePos] == '?')
1429                                                 namePos++;
1430                                 }
1431                                 
1432                                 string name, value;
1433                                 if (valuePos == -1) {
1434                                         name = null;
1435                                         valuePos = namePos;
1436                                 } else {
1437                                         name = UrlDecode (decoded.Substring (namePos, valuePos - namePos - 1), encoding);
1438                                 }
1439                                 if (valueEnd < 0) {
1440                                         namePos = -1;
1441                                         valueEnd = decoded.Length;
1442                                 } else {
1443                                         namePos = valueEnd + 1;
1444                                 }
1445                                 value = UrlDecode (decoded.Substring (valuePos, valueEnd - valuePos), encoding);
1446
1447                                 result.Add (name, value);
1448                                 if (namePos == -1)
1449                                         break;
1450                         }
1451                 }
1452                 #endregion // Methods
1453         }
1454 }
1455