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