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 static readonly bool[] token_chars = {
82 false, false, false, false, false, false, false, false, false, false, false, false, false, false,
83 false, false, false, false, false, false, false, false, false, false, false, false, false, false,
84 false, false, false, false, false, true, false, true, true, true, true, false, false, false, true,
85 true, false, true, true, false, true, true, true, true, true, true, true, true, true, true, false,
86 false, false, false, false, false, false, true, true, true, true, true, true, true, true, true,
87 true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true,
88 false, false, false, true, true, true, true, true, true, true, true, true, true, true, true, true,
89 true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true,
93 static readonly int last_token_char = token_chars.Length;
98 public Lexer (string stream)
103 public string GetStringValue (Token token)
105 return s.Substring (token.StartPosition, token.EndPosition - token.StartPosition);
108 public string GetStringValue (Token start, Token end)
110 return s.Substring (start.StartPosition, end.EndPosition - start.StartPosition);
113 public string GetQuotedStringValue (Token start)
115 return s.Substring (start.StartPosition + 1, start.EndPosition - start.StartPosition - 2);
118 public string GetRemainingStringValue (int position)
120 return position > s.Length ? null : s.Substring (position);
123 public bool TryGetNumericValue (Token token, out int value)
125 return int.TryParse (GetStringValue (token), out value);
128 public TimeSpan? TryGetTimeSpanValue (Token token)
131 if (TryGetNumericValue (token, out seconds)) {
132 return TimeSpan.FromSeconds (seconds);
138 public bool TryGetDateValue (Token token, out DateTimeOffset value)
140 string text = token == Token.Type.QuotedString ?
141 s.Substring (token.StartPosition + 1, token.EndPosition - token.StartPosition - 2) :
142 GetStringValue (token);
144 const DateTimeStyles DefaultStyles = DateTimeStyles.AssumeUniversal | DateTimeStyles.AllowWhiteSpaces;
147 DateTimeOffset.TryParseExact (text, "r", DateTimeFormatInfo.InvariantInfo, DefaultStyles, out value) ||
148 DateTimeOffset.TryParseExact (text, "dddd, dd'-'MMM'-'yy HH:mm:ss 'GMT'", DateTimeFormatInfo.InvariantInfo, DefaultStyles, out value) ||
149 DateTimeOffset.TryParseExact (text, "ddd MMM d HH:mm:ss yyyy", DateTimeFormatInfo.InvariantInfo, DefaultStyles, out value);
152 public static bool IsValidToken (string input)
156 // any CHAR except CTLs or separator
158 for (; i < input.Length; ++i) {
160 if (s > last_token_char || !token_chars[s])
167 public void EatChar ()
172 public int PeekChar ()
174 return pos < s.Length ? s[pos] : -1;
177 public bool ScanCommentOptional (out string value)
180 if (t != Token.Type.OpenParens) {
182 return t == Token.Type.End;
185 while (pos < s.Length) {
189 var start = t.StartPosition;
190 value = s.Substring (start, pos - start);
194 // any OCTET except CTLs, but including LWS
195 if (ch < 32 || ch > 126)
209 return new Token (Token.Type.Error, 0, 0);
212 if (pos >= s.Length) {
213 ttype = Token.Type.End;
215 ttype = Token.Type.Error;
221 if (pos == s.Length) {
222 ttype = Token.Type.End;
228 ttype = Token.Type.SeparatorEqual;
231 ttype = Token.Type.SeparatorSemicolon;
234 ttype = Token.Type.SeparatorSlash;
237 ttype = Token.Type.SeparatorDash;
240 ttype = Token.Type.SeparatorComma;
245 while (pos < s.Length) {
249 ttype = Token.Type.QuotedString;
253 // any OCTET except CTLs, but including LWS
254 if (ch < 32 || ch > 126)
263 ttype = Token.Type.OpenParens;
266 if (ch <= last_token_char && token_chars[ch]) {
269 ttype = Token.Type.Token;
270 while (pos < s.Length) {
272 if (ch > last_token_char || !token_chars[ch]) {
284 return new Token (ttype, start, pos);