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
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 string GetStringValue (Token token)
119 return s.Substring (token.StartPosition, token.EndPosition - token.StartPosition);
122 public string GetStringValue (Token start, Token end)
124 return s.Substring (start.StartPosition, end.EndPosition - start.StartPosition);
127 public string GetQuotedStringValue (Token start)
129 return s.Substring (start.StartPosition + 1, start.EndPosition - start.StartPosition - 2);
132 public string GetRemainingStringValue (int position)
134 return position > s.Length ? null : s.Substring (position);
137 public bool IsStarStringValue (Token token)
139 return (token.EndPosition - token.StartPosition) == 1 && s[token.StartPosition] == '*';
142 public bool TryGetNumericValue (Token token, out int value)
144 return int.TryParse (GetStringValue (token), NumberStyles.None, CultureInfo.InvariantCulture, out value);
147 public TimeSpan? TryGetTimeSpanValue (Token token)
150 if (TryGetNumericValue (token, out seconds)) {
151 return TimeSpan.FromSeconds (seconds);
157 public bool TryGetDateValue (Token token, out DateTimeOffset value)
159 string text = token == Token.Type.QuotedString ?
160 s.Substring (token.StartPosition + 1, token.EndPosition - token.StartPosition - 2) :
161 GetStringValue (token);
163 return TryGetDateValue (text, out value);
166 public static bool TryGetDateValue (string text, out DateTimeOffset value)
168 const DateTimeStyles DefaultStyles = DateTimeStyles.AssumeUniversal | DateTimeStyles.AllowWhiteSpaces;
170 return DateTimeOffset.TryParseExact (text, dt_formats, DateTimeFormatInfo.InvariantInfo, DefaultStyles, out value);
173 public bool TryGetDoubleValue (Token token, out double value)
175 string s = GetStringValue (token);
176 return double.TryParse (s, NumberStyles.AllowDecimalPoint, CultureInfo.InvariantCulture, out value);
179 public static bool IsValidToken (string input)
183 // any CHAR except CTLs or separator
185 for (; i < input.Length; ++i) {
187 if (s > last_token_char || !token_chars[s])
194 public void EatChar ()
199 public int PeekChar ()
201 return pos < s.Length ? s[pos] : -1;
204 public bool ScanCommentOptional (out string value)
207 if (ScanCommentOptional (out value, out t))
210 return t == Token.Type.End;
213 public bool ScanCommentOptional (out string value, out Token readToken)
216 if (readToken != Token.Type.OpenParens) {
221 while (pos < s.Length) {
225 var start = readToken.StartPosition;
226 value = s.Substring (start, pos - start);
230 // any OCTET except CTLs, but including LWS
231 if (ch < 32 || ch > 126)
245 return new Token (Token.Type.Error, 0, 0);
248 if (pos >= s.Length) {
249 ttype = Token.Type.End;
251 ttype = Token.Type.Error;
257 if (pos == s.Length) {
258 ttype = Token.Type.End;
264 ttype = Token.Type.SeparatorEqual;
267 ttype = Token.Type.SeparatorSemicolon;
270 ttype = Token.Type.SeparatorSlash;
273 ttype = Token.Type.SeparatorDash;
276 ttype = Token.Type.SeparatorComma;
281 while (pos < s.Length) {
285 ttype = Token.Type.QuotedString;
289 // any OCTET except CTLs, but including LWS
290 if (ch < 32 || ch > 126)
299 ttype = Token.Type.OpenParens;
302 if (ch <= last_token_char && token_chars[ch]) {
305 ttype = Token.Type.Token;
306 while (pos < s.Length) {
308 if (ch > last_token_char || !token_chars[ch]) {
320 return new Token (ttype, start, pos);