Implemented overloaded versions of Parse and TryParse functions for BigInteger.
[mono.git] / mcs / class / System.Net.Http / System.Net.Http.Headers / Lexer.cs
1 //
2 // Lexer.cs
3 //
4 // Authors:
5 //      Marek Safar  <marek.safar@gmail.com>
6 //
7 // Copyright (C) 2011 Xamarin Inc (http://www.xamarin.com)
8 //
9 // Permission is hereby granted, free of charge, to any person obtaining
10 // a copy of this software and associated documentation files (the
11 // "Software"), to deal in the Software without restriction, including
12 // without limitation the rights to use, copy, modify, merge, publish,
13 // distribute, sublicense, and/or sell copies of the Software, and to
14 // permit persons to whom the Software is furnished to do so, subject to
15 // the following conditions:
16 //
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
19 //
20 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
24 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27 //
28
29 using System.Globalization;
30
31 namespace System.Net.Http.Headers
32 {
33         struct Token
34         {
35                 public enum Type
36                 {
37                         Error,
38                         End,
39                         Token,
40                         QuotedString,
41                         SeparatorEqual,
42                         SeparatorSemicolon,
43                         SeparatorSlash,
44                         SeparatorDash,
45                         SeparatorComma,
46                         OpenParens,
47                 }
48
49                 readonly Type type;
50
51                 public Token (Type type, int startPosition, int endPosition)
52                         : this ()
53                 {
54                         this.type = type;
55                         StartPosition = startPosition;
56                         EndPosition = endPosition;
57                 }
58
59                 public int StartPosition { get; private set; }
60                 public int EndPosition { get; private set; }
61
62                 public Type Kind {
63                         get {
64                                 return type;
65                         }
66                 }
67
68                 public static implicit operator Token.Type (Token token)
69                 {
70                         return token.type;
71                 }
72
73                 public override string ToString ()
74                 {
75                         return type.ToString ();
76                 }
77         }
78
79         class Lexer
80         {
81                 // any CHAR except CTLs or separators
82                 static readonly bool[] token_chars = {
83                         /*0*/   false, false, false, false, false, false, false, false, false, false,
84                         /*10*/  false, false, false, false, false, false, false, false, false, false,
85                         /*20*/  false, false, false, false, false, false, false, false, false, false,
86                         /*30*/  false, false, false, true, false, true, true, true, true, true,
87                         /*40*/  false, false, true, true, false, true, true, false, true, true,
88                         /*50*/  true, true, true, true, true, true, true, true, false, false,
89                         /*60*/  false, false, false, false, false, true, true, true, true, true,
90                         /*70*/  true, true, true, true, true, true, true, true, true, true,
91                         /*80*/  true, true, true, true, true, true, true, true, true, true,
92                         /*90*/  true, false, false, false, true, true, true, true, true, true,
93                         /*100*/ true, true, true, true, true, true, true, true, true, true,
94                         /*110*/ true, true, true, true, true, true, true, true, true, true,
95                         /*120*/ true, true, true, false, true, false
96                         };
97
98                 static readonly int last_token_char = token_chars.Length;
99                 static readonly string[] dt_formats = new[] {
100                                 "r",
101                                 "dddd, dd'-'MMM'-'yy HH:mm:ss 'GMT'",
102                                 "ddd MMM d HH:mm:ss yyyy",
103                                 "d MMM yy H:m:s",
104                                 "ddd, d MMM yyyy H:m:s zzz"
105                 };
106
107                 readonly string s;
108                 int pos;
109
110                 public Lexer (string stream)
111                 {
112                         this.s = stream;
113                 }
114
115                 public string GetStringValue (Token token)
116                 {
117                         return s.Substring (token.StartPosition, token.EndPosition - token.StartPosition);
118                 }
119
120                 public string GetStringValue (Token start, Token end)
121                 {
122                         return s.Substring (start.StartPosition, end.EndPosition - start.StartPosition);
123                 }
124
125                 public string GetQuotedStringValue (Token start)
126                 {
127                         return s.Substring (start.StartPosition + 1, start.EndPosition - start.StartPosition - 2);
128                 }
129
130                 public string GetRemainingStringValue (int position)
131                 {
132                         return position > s.Length ? null : s.Substring (position);
133                 }
134
135                 public bool IsStarStringValue (Token token)
136                 {
137                         return (token.EndPosition - token.StartPosition) == 1 && s[token.StartPosition] == '*';
138                 }
139
140                 public bool TryGetNumericValue (Token token, out int value)
141                 {
142                         return int.TryParse (GetStringValue (token), NumberStyles.None, CultureInfo.InvariantCulture, out value);
143                 }
144
145                 public TimeSpan? TryGetTimeSpanValue (Token token)
146                 {
147                         int seconds;
148                         if (TryGetNumericValue (token, out seconds)) {
149                                 return TimeSpan.FromSeconds (seconds);
150                         }
151
152                         return null;
153                 }
154
155                 public bool TryGetDateValue (Token token, out DateTimeOffset value)
156                 {
157                         string text = token == Token.Type.QuotedString ?
158                                 s.Substring (token.StartPosition + 1, token.EndPosition - token.StartPosition - 2) :
159                                 GetStringValue (token);
160
161                         return TryGetDateValue (text, out value);
162                 }
163
164                 public static bool TryGetDateValue (string text, out DateTimeOffset value)
165                 {
166                         const DateTimeStyles DefaultStyles = DateTimeStyles.AssumeUniversal | DateTimeStyles.AllowWhiteSpaces;
167
168                         return DateTimeOffset.TryParseExact (text, dt_formats, DateTimeFormatInfo.InvariantInfo, DefaultStyles, out value);
169                 }
170
171                 public bool TryGetDoubleValue (Token token, out double value)
172                 {
173                         string s = GetStringValue (token);
174                         return double.TryParse (s, NumberStyles.AllowDecimalPoint, CultureInfo.InvariantCulture, out value);
175                 }
176
177                 public static bool IsValidToken (string input)
178                 {
179                         int i = 0;
180                         //
181                         // any CHAR except CTLs or separator
182                         //
183                         for (; i < input.Length; ++i) {
184                                 char s = input[i];
185                                 if (s > last_token_char || !token_chars[s])
186                                         return false;
187                         }
188
189                         return i > 0;
190                 }
191
192                 public void EatChar ()
193                 {
194                         ++pos;
195                 }
196
197                 public int PeekChar ()
198                 {
199                         return pos < s.Length ? s[pos] : -1;
200                 }
201
202                 public bool ScanCommentOptional (out string value)
203                 {
204                         Token t;
205                         if (ScanCommentOptional (out value, out t))
206                                 return true;
207
208                         return t == Token.Type.End;
209                 }
210
211                 public bool ScanCommentOptional (out string value, out Token readToken)
212                 {
213                         readToken = Scan ();
214                         if (readToken != Token.Type.OpenParens) {
215                                 value = null;
216                                 return false;
217                         }
218
219                         while (pos < s.Length) {
220                                 var ch = s[pos];
221                                 if (ch == ')') {
222                                         ++pos;
223                                         var start = readToken.StartPosition;
224                                         value = s.Substring (start, pos - start);
225                                         return true;
226                                 }
227
228                                 // any OCTET except CTLs, but including LWS
229                                 if (ch < 32 || ch > 126)
230                                         break;
231
232                                 ++pos;
233                         }
234
235                         value = null;
236                         return false;
237                 }
238
239                 public Token Scan ()
240                 {
241                         int start = pos;
242                         if (s == null)
243                                 return new Token (Token.Type.Error, 0, 0);
244
245                         Token.Type ttype;
246                         if (pos >= s.Length) {
247                                 ttype = Token.Type.End;
248                         } else {
249                                 ttype = Token.Type.Error;
250                         start:
251                                 char ch = s[pos++];
252                                 switch (ch) {
253                                 case ' ':
254                                 case '\t':
255                                         if (pos == s.Length) {
256                                                 ttype = Token.Type.End;
257                                                 break;
258                                         }
259
260                                         goto start;
261                                 case '=':
262                                         ttype = Token.Type.SeparatorEqual;
263                                         break;
264                                 case ';':
265                                         ttype = Token.Type.SeparatorSemicolon;
266                                         break;
267                                 case '/':
268                                         ttype = Token.Type.SeparatorSlash;
269                                         break;
270                                 case '-':
271                                         ttype = Token.Type.SeparatorDash;
272                                         break;
273                                 case ',':
274                                         ttype = Token.Type.SeparatorComma;
275                                         break;
276                                 case '"':
277                                         // Quoted string
278                                         start = pos - 1;
279                                         while (pos < s.Length) {
280                                                 ch = s[pos];
281                                                 if (ch == '"') {
282                                                         ++pos;
283                                                         ttype = Token.Type.QuotedString;
284                                                         break;
285                                                 }
286
287                                                 // any OCTET except CTLs, but including LWS
288                                                 if (ch < 32 || ch > 126)
289                                                         break;
290
291                                                 ++pos;
292                                         }
293
294                                         break;
295                                 case '(':
296                                         start = pos - 1;
297                                         ttype = Token.Type.OpenParens;
298                                         break;
299                                 default:
300                                         if (ch <= last_token_char && token_chars[ch]) {
301                                                 start = pos - 1;
302
303                                                 ttype = Token.Type.Token;
304                                                 while (pos < s.Length) {
305                                                         ch = s[pos];
306                                                         if (ch > last_token_char || !token_chars[ch]) {
307                                                                 break;
308                                                         }
309
310                                                         ++pos;
311                                                 }
312                                         }
313
314                                         break;
315                                 }
316                         }
317
318                         return new Token (ttype, start, pos);
319                 }
320         }
321 }