5 // Marek Safar <marek.safar@gmail.com>
7 // Copyright (C) 2011 Xamarin Inc (http://www.xamarin.com)
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:
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
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.
29 using System.Globalization;
31 namespace System.Net.Http.Headers
49 public static readonly Token Empty = new Token (Type.Token, 0, 0);
53 public Token (Type type, int startPosition, int endPosition)
57 StartPosition = startPosition;
58 EndPosition = endPosition;
61 public int StartPosition { get; private set; }
62 public int EndPosition { get; private set; }
70 public static implicit operator Token.Type (Token token)
75 public override string ToString ()
77 return type.ToString ();
83 // any CHAR except CTLs or separators
84 static readonly bool[] token_chars = {
85 /*0*/ false, false, false, false, false, false, false, false, false, false,
86 /*10*/ false, false, false, false, false, false, false, false, false, false,
87 /*20*/ false, false, false, false, false, false, false, false, false, false,
88 /*30*/ false, false, false, true, false, true, true, true, true, true,
89 /*40*/ false, false, true, true, false, true, true, false, true, true,
90 /*50*/ true, true, true, true, true, true, true, true, false, false,
91 /*60*/ false, false, false, false, false, true, true, true, true, true,
92 /*70*/ true, true, true, true, true, true, true, true, true, true,
93 /*80*/ true, true, true, true, true, true, true, true, true, true,
94 /*90*/ true, false, false, false, true, true, true, true, true, true,
95 /*100*/ true, true, true, true, true, true, true, true, true, true,
96 /*110*/ true, true, true, true, true, true, true, true, true, true,
97 /*120*/ true, true, true, false, true, false, true
100 static readonly int last_token_char = token_chars.Length;
101 static readonly string[] dt_formats = new[] {
103 "dddd, dd'-'MMM'-'yy HH:mm:ss 'GMT'",
104 "ddd MMM d HH:mm:ss yyyy",
106 "ddd, d MMM yyyy H:m:s zzz"
112 public Lexer (string stream)
117 public int Position {
126 public string GetStringValue (Token token)
128 return s.Substring (token.StartPosition, token.EndPosition - token.StartPosition);
131 public string GetStringValue (Token start, Token end)
133 return s.Substring (start.StartPosition, end.EndPosition - start.StartPosition);
136 public string GetQuotedStringValue (Token start)
138 return s.Substring (start.StartPosition + 1, start.EndPosition - start.StartPosition - 2);
141 public string GetRemainingStringValue (int position)
143 return position > s.Length ? null : s.Substring (position);
146 public bool IsStarStringValue (Token token)
148 return (token.EndPosition - token.StartPosition) == 1 && s[token.StartPosition] == '*';
151 public bool TryGetNumericValue (Token token, out int value)
153 return int.TryParse (GetStringValue (token), NumberStyles.None, CultureInfo.InvariantCulture, out value);
156 public TimeSpan? TryGetTimeSpanValue (Token token)
159 if (TryGetNumericValue (token, out seconds)) {
160 return TimeSpan.FromSeconds (seconds);
166 public bool TryGetDateValue (Token token, out DateTimeOffset value)
168 string text = token == Token.Type.QuotedString ?
169 s.Substring (token.StartPosition + 1, token.EndPosition - token.StartPosition - 2) :
170 GetStringValue (token);
172 return TryGetDateValue (text, out value);
175 public static bool TryGetDateValue (string text, out DateTimeOffset value)
177 const DateTimeStyles DefaultStyles = DateTimeStyles.AssumeUniversal | DateTimeStyles.AllowWhiteSpaces;
179 return DateTimeOffset.TryParseExact (text, dt_formats, DateTimeFormatInfo.InvariantInfo, DefaultStyles, out value);
182 public bool TryGetDoubleValue (Token token, out double value)
184 string s = GetStringValue (token);
185 return double.TryParse (s, NumberStyles.AllowDecimalPoint, CultureInfo.InvariantCulture, out value);
188 public static bool IsValidToken (string input)
192 // any CHAR except CTLs or separator
194 for (; i < input.Length; ++i) {
196 if (!IsValidCharacter (s))
203 public static bool IsValidCharacter (char input)
205 return input < last_token_char && token_chars[input];
208 public void EatChar ()
213 public int PeekChar ()
215 return pos < s.Length ? s[pos] : -1;
218 public bool ScanCommentOptional (out string value)
221 if (ScanCommentOptional (out value, out t))
224 return t == Token.Type.End;
227 public bool ScanCommentOptional (out string value, out Token readToken)
230 if (readToken != Token.Type.OpenParens) {
236 while (pos < s.Length) {
249 var start = readToken.StartPosition;
250 value = s.Substring (start, pos - start);
254 // any OCTET except CTLs, but including LWS
255 if (ch < 32 || ch > 126)
265 public Token Scan (bool recognizeDash = false)
269 return new Token (Token.Type.Error, 0, 0);
272 if (pos >= s.Length) {
273 ttype = Token.Type.End;
275 ttype = Token.Type.Error;
281 if (pos == s.Length) {
282 ttype = Token.Type.End;
288 ttype = Token.Type.SeparatorEqual;
291 ttype = Token.Type.SeparatorSemicolon;
294 ttype = Token.Type.SeparatorSlash;
298 ttype = Token.Type.SeparatorDash;
304 ttype = Token.Type.SeparatorComma;
309 while (pos < s.Length) {
312 ttype = Token.Type.QuotedString;
320 ttype = Token.Type.OpenParens;
323 if (ch < last_token_char && token_chars[ch]) {
326 ttype = Token.Type.Token;
327 while (pos < s.Length) {
329 if (ch >= last_token_char || !token_chars[ch]) {
341 return new Token (ttype, start, pos);