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
51 public Token (Type type, int startPosition, int endPosition)
55 StartPosition = startPosition;
56 EndPosition = endPosition;
59 public int StartPosition { get; private set; }
60 public int EndPosition { get; private set; }
68 public static implicit operator Token.Type (Token token)
73 public override string ToString ()
75 return type.ToString ();
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
98 static readonly int last_token_char = token_chars.Length;
99 static readonly string[] dt_formats = new[] {
101 "dddd, dd'-'MMM'-'yy HH:mm:ss 'GMT'",
102 "ddd MMM d HH:mm:ss yyyy",
104 "ddd, d MMM yyyy H:m:s zzz"
110 public Lexer (string stream)
115 public string GetStringValue (Token token)
117 return s.Substring (token.StartPosition, token.EndPosition - token.StartPosition);
120 public string GetStringValue (Token start, Token end)
122 return s.Substring (start.StartPosition, end.EndPosition - start.StartPosition);
125 public string GetQuotedStringValue (Token start)
127 return s.Substring (start.StartPosition + 1, start.EndPosition - start.StartPosition - 2);
130 public string GetRemainingStringValue (int position)
132 return position > s.Length ? null : s.Substring (position);
135 public bool IsStarStringValue (Token token)
137 return (token.EndPosition - token.StartPosition) == 1 && s[token.StartPosition] == '*';
140 public bool TryGetNumericValue (Token token, out int value)
142 return int.TryParse (GetStringValue (token), NumberStyles.None, CultureInfo.InvariantCulture, out value);
145 public TimeSpan? TryGetTimeSpanValue (Token token)
148 if (TryGetNumericValue (token, out seconds)) {
149 return TimeSpan.FromSeconds (seconds);
155 public bool TryGetDateValue (Token token, out DateTimeOffset value)
157 string text = token == Token.Type.QuotedString ?
158 s.Substring (token.StartPosition + 1, token.EndPosition - token.StartPosition - 2) :
159 GetStringValue (token);
161 return TryGetDateValue (text, out value);
164 public static bool TryGetDateValue (string text, out DateTimeOffset value)
166 const DateTimeStyles DefaultStyles = DateTimeStyles.AssumeUniversal | DateTimeStyles.AllowWhiteSpaces;
168 return DateTimeOffset.TryParseExact (text, dt_formats, DateTimeFormatInfo.InvariantInfo, DefaultStyles, out value);
171 public bool TryGetDoubleValue (Token token, out double value)
173 string s = GetStringValue (token);
174 return double.TryParse (s, NumberStyles.AllowDecimalPoint, CultureInfo.InvariantCulture, out value);
177 public static bool IsValidToken (string input)
181 // any CHAR except CTLs or separator
183 for (; i < input.Length; ++i) {
185 if (s > last_token_char || !token_chars[s])
192 public void EatChar ()
197 public int PeekChar ()
199 return pos < s.Length ? s[pos] : -1;
202 public bool ScanCommentOptional (out string value)
205 if (ScanCommentOptional (out value, out t))
208 return t == Token.Type.End;
211 public bool ScanCommentOptional (out string value, out Token readToken)
214 if (readToken != Token.Type.OpenParens) {
219 while (pos < s.Length) {
223 var start = readToken.StartPosition;
224 value = s.Substring (start, pos - start);
228 // any OCTET except CTLs, but including LWS
229 if (ch < 32 || ch > 126)
243 return new Token (Token.Type.Error, 0, 0);
246 if (pos >= s.Length) {
247 ttype = Token.Type.End;
249 ttype = Token.Type.Error;
255 if (pos == s.Length) {
256 ttype = Token.Type.End;
262 ttype = Token.Type.SeparatorEqual;
265 ttype = Token.Type.SeparatorSemicolon;
268 ttype = Token.Type.SeparatorSlash;
271 ttype = Token.Type.SeparatorDash;
274 ttype = Token.Type.SeparatorComma;
279 while (pos < s.Length) {
283 ttype = Token.Type.QuotedString;
287 // any OCTET except CTLs, but including LWS
288 if (ch < 32 || ch > 126)
297 ttype = Token.Type.OpenParens;
300 if (ch <= last_token_char && token_chars[ch]) {
303 ttype = Token.Type.Token;
304 while (pos < s.Length) {
306 if (ch > last_token_char || !token_chars[ch]) {
318 return new Token (ttype, start, pos);