[runtime] Updates comments.
[mono.git] / mcs / class / System.Net.Http / System.Net.Http.Headers / RangeHeaderValue.cs
1 //
2 // RangeHeaderValue.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.Collections.Generic;
30 using System.Text;
31
32 namespace System.Net.Http.Headers
33 {
34         public class RangeHeaderValue : ICloneable
35         {
36                 List<RangeItemHeaderValue> ranges;
37                 string unit;
38
39                 public RangeHeaderValue ()
40                 {
41                         unit = "bytes";
42                 }
43
44                 public RangeHeaderValue (long? from, long? to)
45                         : this ()
46                 {
47                         Ranges.Add (new RangeItemHeaderValue (from, to));
48                 }
49
50                 private RangeHeaderValue (RangeHeaderValue source)
51                         : this ()
52                 {
53                         if (source.ranges != null) {
54                                 foreach (var item in source.ranges)
55                                         Ranges.Add (item);
56                         }
57                 }
58
59                 public ICollection<RangeItemHeaderValue> Ranges {
60                         get {
61                                 return ranges ?? (ranges = new List<RangeItemHeaderValue> ());
62                         }
63                 }
64
65                 public string Unit {
66                         get {
67                                 return unit;
68                         }
69                         set {
70                                 if (value == null)
71                                         throw new ArgumentNullException ("Unit");
72
73                                 Parser.Token.Check (value);
74
75                                 unit = value;
76                         }
77                 }
78
79                 object ICloneable.Clone ()
80                 {
81                         return new RangeHeaderValue (this);
82                 }
83
84                 public override bool Equals (object obj)
85                 {
86                         var source = obj as RangeHeaderValue;
87                         if (source == null)
88                                 return false;
89
90                         return string.Equals (source.Unit, Unit, StringComparison.OrdinalIgnoreCase) &&
91                                 source.ranges.SequenceEqual (ranges);
92                 }
93
94                 public override int GetHashCode ()
95                 {
96                         return Unit.ToLowerInvariant ().GetHashCode () ^ HashCodeCalculator.Calculate (ranges);
97                 }
98
99                 public static RangeHeaderValue Parse (string input)
100                 {
101                         RangeHeaderValue value;
102                         if (TryParse (input, out value))
103                                 return value;
104
105                         throw new FormatException (input);
106                 }
107
108                 public static bool TryParse (string input, out RangeHeaderValue parsedValue)
109                 {
110                         parsedValue = null;
111
112                         var lexer = new Lexer (input);
113                         var t = lexer.Scan ();
114                         if (t != Token.Type.Token)
115                                 return false;
116
117                         var value = new RangeHeaderValue ();
118                         value.unit = lexer.GetStringValue (t);
119
120                         t = lexer.Scan ();
121                         if (t != Token.Type.SeparatorEqual)
122                                 return false;
123
124                         bool token_read;
125                         do {
126                                 int? from = null, to = null;
127                                 int number;
128                                 token_read = false;
129
130                                 t = lexer.Scan (recognizeDash: true);
131                                 switch (t.Kind) {
132                                 case Token.Type.SeparatorDash:
133                                         t = lexer.Scan ();
134                                         if (!lexer.TryGetNumericValue (t, out number))
135                                                 return false;
136
137                                         to = number;
138                                         break;
139                                 case Token.Type.Token:
140                                         string s = lexer.GetStringValue (t);
141                                         var values = s.Split (new [] { '-' }, StringSplitOptions.RemoveEmptyEntries);
142                                         if (!int.TryParse (values[0], out number))
143                                                 return false;
144
145                                         switch (values.Length) {
146                                         case 1:
147                                                 t = lexer.Scan (recognizeDash: true);
148                                                 from = number;
149                                                 switch (t.Kind) {
150                                                 case Token.Type.SeparatorDash:
151                                                         t = lexer.Scan ();
152                                                         if (t != Token.Type.Token) {
153                                                                 token_read = true;
154                                                                 break;
155                                                         }
156
157                                                         if (!lexer.TryGetNumericValue (t, out number))
158                                                                 return false;
159
160                                                         to = number;
161                                                         if (to < from)
162                                                                 return false;
163
164                                                         break;
165                                                 case Token.Type.End:
166                                                         if (s.Length > 0 && s [s.Length - 1] != '-')
167                                                                 return false;
168
169                                                         token_read = true;
170                                                         break;
171                                                 case Token.Type.SeparatorComma:
172                                                         token_read = true;
173                                                         break;
174                                                 default:
175                                                         return false;
176                                                 }
177                                                 break;
178                                         case 2:
179                                                 from = number;
180
181                                                 if (!int.TryParse (values[1], out number))
182                                                         return false;
183
184                                                 to = number;
185                                                 if (to < from)
186                                                         return false;
187
188                                                 break;
189                                         default:
190                                                 return false;
191                                         }
192
193                                         break;
194                                 default:
195                                         return false;
196                                 }
197
198                                 value.Ranges.Add (new RangeItemHeaderValue (from, to));
199                                 if (!token_read)
200                                         t = lexer.Scan ();
201
202                         } while (t == Token.Type.SeparatorComma);
203
204                         if (t != Token.Type.End)
205                                 return false;
206
207                         parsedValue = value;
208                         return true;
209                 }
210
211                 public override string ToString ()
212                 {
213                         var sb = new StringBuilder (unit);
214                         sb.Append ("=");
215                         for (int i = 0; i < Ranges.Count; ++i) {
216                                 if (i > 0)
217                                         sb.Append (", ");
218
219                                 sb.Append (ranges[i]);
220                         }
221
222                         return sb.ToString ();
223                 }
224         }
225 }