wasSharp – Diff between revs 17 and 27
?pathlinks?
Rev 17 | Rev 27 | |||
---|---|---|---|---|
1 | // The MIT License (MIT) |
1 | // The MIT License (MIT) |
|
2 | // |
2 | // |
|
3 | // Copyright (c) 2015 Dave Transom |
3 | // Copyright (c) 2015 Dave Transom |
|
4 | // |
4 | // |
|
5 | // Permission is hereby granted, free of charge, to any person obtaining a |
5 | // Permission is hereby granted, free of charge, to any person obtaining a |
|
6 | // copy of this software and associated documentation files (the |
6 | // copy of this software and associated documentation files (the |
|
7 | // "Software"), to deal in the Software without restriction, including |
7 | // "Software"), to deal in the Software without restriction, including |
|
8 | // without limitation the rights to use, copy, modify, merge, publish, |
8 | // without limitation the rights to use, copy, modify, merge, publish, |
|
9 | // distribute, sublicense, and/or sell copies of the Software, and to |
9 | // distribute, sublicense, and/or sell copies of the Software, and to |
|
10 | // permit persons to whom the Software is furnished to do so, subject to |
10 | // permit persons to whom the Software is furnished to do so, subject to |
|
11 | // the following conditions: |
11 | // the following conditions: |
|
12 | // |
12 | // |
|
13 | // The above copyright notice and this permission notice shall be included |
13 | // The above copyright notice and this permission notice shall be included |
|
14 | // in all copies or substantial portions of the Software. |
14 | // in all copies or substantial portions of the Software. |
|
15 | // |
15 | // |
|
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS |
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS |
|
17 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
17 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
|
18 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. |
18 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. |
|
19 | // IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY |
19 | // IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY |
|
20 | // CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, |
20 | // CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, |
|
21 | // TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE |
21 | // TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE |
|
22 | // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
22 | // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
|
23 | |
23 | |
|
24 | // For background refer to this article by Dave Transom |
24 | // For background refer to this article by Dave Transom |
|
25 | // http://www.singular.co.nz/2008/07/finding-preferred-accept-encoding-header-in-csharp/ |
25 | // http://www.singular.co.nz/2008/07/finding-preferred-accept-encoding-header-in-csharp/ |
|
26 | |
26 | |
|
27 | using System; |
27 | using System; |
|
28 | using System.Collections.Generic; |
28 | using System.Collections.Generic; |
|
29 | using System.Diagnostics; |
29 | using System.Diagnostics; |
|
30 | using System.Globalization; |
30 | using System.Globalization; |
|
31 | |
31 | |
|
32 | namespace wasSharp.Web |
32 | namespace wasSharp.Web |
|
33 | { |
33 | { |
|
34 | /// <summary> |
34 | /// <summary> |
|
35 | /// Represents a weighted value (or quality value) from an http header e.g. gzip=0.9; deflate; x-gzip=0.5; |
35 | /// Represents a weighted value (or quality value) from an http header e.g. gzip=0.9; deflate; x-gzip=0.5; |
|
36 | /// </summary> |
36 | /// </summary> |
|
37 | /// <remarks> |
37 | /// <remarks> |
|
38 | /// accept-encoding spec: |
38 | /// accept-encoding spec: |
|
39 | /// http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html |
39 | /// http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html |
|
40 | /// </remarks> |
40 | /// </remarks> |
|
41 | /// <example> |
41 | /// <example> |
|
42 | /// Accept: |
42 | /// Accept: |
|
43 | /// text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5 |
43 | /// text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5 |
|
44 | /// Accept-Encoding: gzip,deflate |
44 | /// Accept-Encoding: gzip,deflate |
|
45 | /// Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7 |
45 | /// Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7 |
|
46 | /// Accept-Language: en-us,en;q=0.5 |
46 | /// Accept-Language: en-us,en;q=0.5 |
|
47 | /// </example> |
47 | /// </example> |
|
48 | [DebuggerDisplay("QValue[{Name}, {Weight}]")] |
48 | [DebuggerDisplay("QValue[{Name}, {Weight}]")] |
|
49 | public struct QValue : IComparable<QValue> |
49 | public struct QValue : IComparable<QValue> |
|
50 | { |
50 | { |
|
51 | private static readonly char[] delimiters = {';', '='}; |
51 | private static readonly char[] delimiters = { ';', '=' }; |
|
52 | private const float defaultWeight = 1; |
52 | private const float defaultWeight = 1; |
|
53 | |
53 | |
|
54 | #region Fields |
54 | #region Fields |
|
55 | |
55 | |
|
56 | private float _weight; |
56 | private float _weight; |
|
57 | private int _ordinal; |
57 | private int _ordinal; |
|
58 | |
58 | |
|
59 | #endregion |
59 | #endregion Fields |
|
60 | |
60 | |
|
61 | #region Constructors |
61 | #region Constructors |
|
62 | |
62 | |
|
63 | /// <summary> |
63 | /// <summary> |
|
64 | /// Creates a new QValue by parsing the given value |
64 | /// Creates a new QValue by parsing the given value |
|
65 | /// for name and weight (qvalue) |
65 | /// for name and weight (qvalue) |
|
66 | /// </summary> |
66 | /// </summary> |
|
67 | /// <param name="value">The value to be parsed e.g. gzip=0.3</param> |
67 | /// <param name="value">The value to be parsed e.g. gzip=0.3</param> |
|
68 | public QValue(string value) |
68 | public QValue(string value) |
|
69 | : this(value, 0) |
69 | : this(value, 0) |
|
70 | { |
70 | { |
|
71 | } |
71 | } |
|
72 | |
72 | |
|
73 | /// <summary> |
73 | /// <summary> |
|
74 | /// Creates a new QValue by parsing the given value |
74 | /// Creates a new QValue by parsing the given value |
|
75 | /// for name and weight (qvalue) and assigns the given |
75 | /// for name and weight (qvalue) and assigns the given |
|
76 | /// ordinal |
76 | /// ordinal |
|
77 | /// </summary> |
77 | /// </summary> |
|
78 | /// <param name="value">The value to be parsed e.g. gzip=0.3</param> |
78 | /// <param name="value">The value to be parsed e.g. gzip=0.3</param> |
|
79 | /// <param name="ordinal"> |
79 | /// <param name="ordinal"> |
|
80 | /// The ordinal/index where the item |
80 | /// The ordinal/index where the item |
|
81 | /// was found in the original list. |
81 | /// was found in the original list. |
|
82 | /// </param> |
82 | /// </param> |
|
83 | public QValue(string value, int ordinal) |
83 | public QValue(string value, int ordinal) |
|
84 | { |
84 | { |
|
85 | Name = null; |
85 | Name = null; |
|
86 | _weight = 0; |
86 | _weight = 0; |
|
87 | _ordinal = ordinal; |
87 | _ordinal = ordinal; |
|
88 | |
88 | |
|
89 | ParseInternal(ref this, value); |
89 | ParseInternal(ref this, value); |
|
90 | } |
90 | } |
|
91 | |
91 | |
|
92 | #endregion |
92 | #endregion Constructors |
|
93 | |
93 | |
|
94 | #region Properties |
94 | #region Properties |
|
95 | |
95 | |
|
96 | /// <summary> |
96 | /// <summary> |
|
97 | /// The name of the value part |
97 | /// The name of the value part |
|
98 | /// </summary> |
98 | /// </summary> |
|
99 | public string Name { get; private set; } |
99 | public string Name { get; private set; } |
|
100 | |
100 | |
|
101 | /// <summary> |
101 | /// <summary> |
|
102 | /// The weighting (or qvalue, quality value) of the encoding |
102 | /// The weighting (or qvalue, quality value) of the encoding |
|
103 | /// </summary> |
103 | /// </summary> |
|
104 | public float Weight => _weight; |
104 | public float Weight => _weight; |
|
105 | |
105 | |
|
106 | /// <summary> |
106 | /// <summary> |
|
107 | /// Whether the value can be accepted |
107 | /// Whether the value can be accepted |
|
108 | /// i.e. it's weight is greater than zero |
108 | /// i.e. it's weight is greater than zero |
|
109 | /// </summary> |
109 | /// </summary> |
|
110 | public bool CanAccept => _weight > 0; |
110 | public bool CanAccept => _weight > 0; |
|
111 | |
111 | |
|
112 | /// <summary> |
112 | /// <summary> |
|
113 | /// Whether the value is empty (i.e. has no name) |
113 | /// Whether the value is empty (i.e. has no name) |
|
114 | /// </summary> |
114 | /// </summary> |
|
115 | public bool IsEmpty => string.IsNullOrEmpty(Name); |
115 | public bool IsEmpty => string.IsNullOrEmpty(Name); |
|
116 | |
116 | |
|
117 | #endregion |
117 | #endregion Properties |
|
118 | |
118 | |
|
119 | #region Methods |
119 | #region Methods |
|
120 | |
120 | |
|
121 | /// <summary> |
121 | /// <summary> |
|
122 | /// Parses the given string for name and |
122 | /// Parses the given string for name and |
|
123 | /// weigth (qvalue) |
123 | /// weigth (qvalue) |
|
124 | /// </summary> |
124 | /// </summary> |
|
125 | /// <param name="value">The string to parse</param> |
125 | /// <param name="value">The string to parse</param> |
|
126 | public static QValue Parse(string value) |
126 | public static QValue Parse(string value) |
|
127 | { |
127 | { |
|
128 | var item = new QValue(); |
128 | var item = new QValue(); |
|
129 | ParseInternal(ref item, value); |
129 | ParseInternal(ref item, value); |
|
130 | return item; |
130 | return item; |
|
131 | } |
131 | } |
|
132 | |
132 | |
|
133 | /// <summary> |
133 | /// <summary> |
|
134 | /// Parses the given string for name and |
134 | /// Parses the given string for name and |
|
135 | /// weigth (qvalue) |
135 | /// weigth (qvalue) |
|
136 | /// </summary> |
136 | /// </summary> |
|
137 | /// <param name="value">The string to parse</param> |
137 | /// <param name="value">The string to parse</param> |
|
138 | /// <param name="ordinal">The order of item in sequence</param> |
138 | /// <param name="ordinal">The order of item in sequence</param> |
|
139 | /// <returns></returns> |
139 | /// <returns></returns> |
|
140 | public static QValue Parse(string value, int ordinal) |
140 | public static QValue Parse(string value, int ordinal) |
|
141 | { |
141 | { |
|
142 | var item = Parse(value); |
142 | var item = Parse(value); |
|
143 | item._ordinal = ordinal; |
143 | item._ordinal = ordinal; |
|
144 | return item; |
144 | return item; |
|
145 | } |
145 | } |
|
146 | |
146 | |
|
147 | /// <summary> |
147 | /// <summary> |
|
148 | /// Parses the given string for name and |
148 | /// Parses the given string for name and |
|
149 | /// weigth (qvalue) |
149 | /// weigth (qvalue) |
|
150 | /// </summary> |
150 | /// </summary> |
|
151 | /// <param name="value">The string to parse</param> |
151 | /// <param name="value">The string to parse</param> |
|
152 | private static void ParseInternal(ref QValue target, string value) |
152 | private static void ParseInternal(ref QValue target, string value) |
|
153 | { |
153 | { |
|
154 | var parts = value.Split(delimiters, 3); |
154 | var parts = value.Split(delimiters, 3); |
|
155 | if (parts.Length > 0) |
155 | if (parts.Length > 0) |
|
156 | { |
156 | { |
|
157 | target.Name = parts[0].Trim(); |
157 | target.Name = parts[0].Trim(); |
|
158 | target._weight = defaultWeight; |
158 | target._weight = defaultWeight; |
|
159 | } |
159 | } |
|
160 | |
160 | |
|
161 | if (parts.Length == 3) |
161 | if (parts.Length == 3) |
|
162 | { |
162 | { |
|
163 | float.TryParse(parts[2], NumberStyles.AllowDecimalPoint, CultureInfo.InvariantCulture.NumberFormat, |
163 | float.TryParse(parts[2], NumberStyles.AllowDecimalPoint, CultureInfo.InvariantCulture.NumberFormat, |
|
164 | out target._weight); |
164 | out target._weight); |
|
165 | } |
165 | } |
|
166 | } |
166 | } |
|
167 | |
167 | |
|
168 | #endregion |
168 | #endregion Methods |
|
169 | |
169 | |
|
170 | #region IComparable<QValue> Members |
170 | #region IComparable<QValue> Members |
|
171 | |
171 | |
|
172 | /// <summary> |
172 | /// <summary> |
|
173 | /// Compares this instance to another QValue by |
173 | /// Compares this instance to another QValue by |
|
174 | /// comparing first weights, then ordinals. |
174 | /// comparing first weights, then ordinals. |
|
175 | /// </summary> |
175 | /// </summary> |
|
176 | /// <param name="other">The QValue to compare</param> |
176 | /// <param name="other">The QValue to compare</param> |
|
177 | /// <returns></returns> |
177 | /// <returns></returns> |
|
178 | public int CompareTo(QValue other) |
178 | public int CompareTo(QValue other) |
|
179 | { |
179 | { |
|
180 | var value = _weight.CompareTo(other._weight); |
180 | var value = _weight.CompareTo(other._weight); |
|
181 | if (value == 0) |
181 | if (value == 0) |
|
182 | { |
182 | { |
|
183 | var ord = -_ordinal; |
183 | var ord = -_ordinal; |
|
184 | value = ord.CompareTo(-other._ordinal); |
184 | value = ord.CompareTo(-other._ordinal); |
|
185 | } |
185 | } |
|
186 | return value; |
186 | return value; |
|
187 | } |
187 | } |
|
188 | |
188 | |
|
189 | #endregion |
189 | #endregion IComparable<QValue> Members |
|
190 | |
190 | |
|
191 | #region CompareByWeight |
191 | #region CompareByWeight |
|
192 | |
192 | |
|
193 | /// <summary> |
193 | /// <summary> |
|
194 | /// Compares two QValues in ascending order. |
194 | /// Compares two QValues in ascending order. |
|
195 | /// </summary> |
195 | /// </summary> |
|
196 | /// <param name="x">The first QValue</param> |
196 | /// <param name="x">The first QValue</param> |
|
197 | /// <param name="y">The second QValue</param> |
197 | /// <param name="y">The second QValue</param> |
|
198 | /// <returns></returns> |
198 | /// <returns></returns> |
|
199 | public static int CompareByWeightAsc(QValue x, QValue y) |
199 | public static int CompareByWeightAsc(QValue x, QValue y) |
|
200 | { |
200 | { |
|
201 | return x.CompareTo(y); |
201 | return x.CompareTo(y); |
|
202 | } |
202 | } |
|
203 | |
203 | |
|
204 | /// <summary> |
204 | /// <summary> |
|
205 | /// Compares two QValues in descending order. |
205 | /// Compares two QValues in descending order. |
|
206 | /// </summary> |
206 | /// </summary> |
|
207 | /// <param name="x">The first QValue</param> |
207 | /// <param name="x">The first QValue</param> |
|
208 | /// <param name="y">The second QValue</param> |
208 | /// <param name="y">The second QValue</param> |
|
209 | /// <returns></returns> |
209 | /// <returns></returns> |
|
210 | public static int CompareByWeightDesc(QValue x, QValue y) |
210 | public static int CompareByWeightDesc(QValue x, QValue y) |
|
211 | { |
211 | { |
|
212 | return -x.CompareTo(y); |
212 | return -x.CompareTo(y); |
|
213 | } |
213 | } |
|
214 | |
214 | |
|
215 | #endregion |
215 | #endregion CompareByWeight |
|
216 | } |
216 | } |
|
217 | |
217 | |
|
218 | /// <summary> |
218 | /// <summary> |
|
219 | /// Provides a collection for working with qvalue http headers |
219 | /// Provides a collection for working with qvalue http headers |
|
220 | /// </summary> |
220 | /// </summary> |
|
221 | /// <remarks> |
221 | /// <remarks> |
|
222 | /// accept-encoding spec: |
222 | /// accept-encoding spec: |
|
223 | /// http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html |
223 | /// http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html |
|
224 | /// </remarks> |
224 | /// </remarks> |
|
225 | [DebuggerDisplay("QValue[{Count}, {AcceptWildcard}]")] |
225 | [DebuggerDisplay("QValue[{Count}, {AcceptWildcard}]")] |
|
226 | public sealed class QValueList : List<QValue> |
226 | public sealed class QValueList : List<QValue> |
|
227 | { |
227 | { |
|
228 | private static readonly char[] delimiters = {','}; |
228 | private static readonly char[] delimiters = { ',' }; |
|
229 | |
229 | |
|
230 | #region Add |
230 | #region Add |
|
231 | |
231 | |
|
232 | /// <summary> |
232 | /// <summary> |
|
233 | /// Adds an item to the list, then applies sorting |
233 | /// Adds an item to the list, then applies sorting |
|
234 | /// if AutoSort is enabled. |
234 | /// if AutoSort is enabled. |
|
235 | /// </summary> |
235 | /// </summary> |
|
236 | /// <param name="item">The item to add</param> |
236 | /// <param name="item">The item to add</param> |
|
237 | public new void Add(QValue item) |
237 | public new void Add(QValue item) |
|
238 | { |
238 | { |
|
239 | base.Add(item); |
239 | base.Add(item); |
|
240 | |
240 | |
|
241 | applyAutoSort(); |
241 | applyAutoSort(); |
|
242 | } |
242 | } |
|
243 | |
243 | |
|
244 | #endregion |
244 | #endregion Add |
|
245 | |
245 | |
|
246 | #region AddRange |
246 | #region AddRange |
|
247 | |
247 | |
|
248 | /// <summary> |
248 | /// <summary> |
|
249 | /// Adds a range of items to the list, then applies sorting |
249 | /// Adds a range of items to the list, then applies sorting |
|
250 | /// if AutoSort is enabled. |
250 | /// if AutoSort is enabled. |
|
251 | /// </summary> |
251 | /// </summary> |
|
252 | /// <param name="collection">The items to add</param> |
252 | /// <param name="collection">The items to add</param> |
|
253 | public new void AddRange(IEnumerable<QValue> collection) |
253 | public new void AddRange(IEnumerable<QValue> collection) |
|
254 | { |
254 | { |
|
255 | var state = AutoSort; |
255 | var state = AutoSort; |
|
256 | AutoSort = false; |
256 | AutoSort = false; |
|
257 | |
257 | |
|
258 | base.AddRange(collection); |
258 | base.AddRange(collection); |
|
259 | |
259 | |
|
260 | AutoSort = state; |
260 | AutoSort = state; |
|
261 | applyAutoSort(); |
261 | applyAutoSort(); |
|
262 | } |
262 | } |
|
263 | |
263 | |
|
264 | #endregion |
264 | #endregion AddRange |
|
265 | |
265 | |
|
266 | #region Find |
266 | #region Find |
|
267 | |
267 | |
|
268 | /// <summary> |
268 | /// <summary> |
|
269 | /// Finds the first QValue with the given name (case-insensitive) |
269 | /// Finds the first QValue with the given name (case-insensitive) |
|
270 | /// </summary> |
270 | /// </summary> |
|
271 | /// <param name="name">The name of the QValue to search for</param> |
271 | /// <param name="name">The name of the QValue to search for</param> |
|
272 | /// <returns></returns> |
272 | /// <returns></returns> |
|
273 | public QValue Find(string name) |
273 | public QValue Find(string name) |
|
274 | { |
274 | { |
|
275 | Predicate<QValue> criteria = |
275 | Predicate<QValue> criteria = |
|
276 | item => item.Name.Equals(name, StringComparison.OrdinalIgnoreCase); |
276 | item => item.Name.Equals(name, StringComparison.OrdinalIgnoreCase); |
|
277 | return Find(criteria); |
277 | return Find(criteria); |
|
278 | } |
278 | } |
|
279 | |
279 | |
|
280 | #endregion |
280 | #endregion Find |
|
281 | |
281 | |
|
282 | #region FindHighestWeight |
282 | #region FindHighestWeight |
|
283 | |
283 | |
|
284 | /// <summary> |
284 | /// <summary> |
|
285 | /// Returns the first match found from the given candidates |
285 | /// Returns the first match found from the given candidates |
|
286 | /// </summary> |
286 | /// </summary> |
|
287 | /// <param name="candidates">The list of QValue names to find</param> |
287 | /// <param name="candidates">The list of QValue names to find</param> |
|
288 | /// <returns>The first QValue match to be found</returns> |
288 | /// <returns>The first QValue match to be found</returns> |
|
289 | /// <remarks> |
289 | /// <remarks> |
|
290 | /// Loops from the first item in the list to the last and finds |
290 | /// Loops from the first item in the list to the last and finds |
|
291 | /// the first candidate - the list must be sorted for weight prior to |
291 | /// the first candidate - the list must be sorted for weight prior to |
|
292 | /// calling this method. |
292 | /// calling this method. |
|
293 | /// </remarks> |
293 | /// </remarks> |
|
294 | public QValue FindHighestWeight(params string[] candidates) |
294 | public QValue FindHighestWeight(params string[] candidates) |
|
295 | { |
295 | { |
|
296 | Predicate<QValue> criteria = item => isCandidate(item.Name, candidates); |
296 | Predicate<QValue> criteria = item => isCandidate(item.Name, candidates); |
|
297 | return Find(criteria); |
297 | return Find(criteria); |
|
298 | } |
298 | } |
|
299 | |
299 | |
|
300 | #endregion |
300 | #endregion FindHighestWeight |
|
301 | |
301 | |
|
302 | #region FindPreferred |
302 | #region FindPreferred |
|
303 | |
303 | |
|
304 | /// <summary> |
304 | /// <summary> |
|
305 | /// Returns the first match found from the given candidates that is accepted |
305 | /// Returns the first match found from the given candidates that is accepted |
|
306 | /// </summary> |
306 | /// </summary> |
|
307 | /// <param name="candidates">The list of names to find</param> |
307 | /// <param name="candidates">The list of names to find</param> |
|
308 | /// <returns>The first QValue match to be found</returns> |
308 | /// <returns>The first QValue match to be found</returns> |
|
309 | /// <remarks> |
309 | /// <remarks> |
|
310 | /// Loops from the first item in the list to the last and finds the |
310 | /// Loops from the first item in the list to the last and finds the |
|
311 | /// first candidate that can be accepted - the list must be sorted for weight |
311 | /// first candidate that can be accepted - the list must be sorted for weight |
|
312 | /// prior to calling this method. |
312 | /// prior to calling this method. |
|
313 | /// </remarks> |
313 | /// </remarks> |
|
314 | public QValue FindPreferred(params string[] candidates) |
314 | public QValue FindPreferred(params string[] candidates) |
|
315 | { |
315 | { |
|
316 | Predicate<QValue> criteria = |
316 | Predicate<QValue> criteria = |
|
317 | item => isCandidate(item.Name, candidates) && item.CanAccept; |
317 | item => isCandidate(item.Name, candidates) && item.CanAccept; |
|
318 | return Find(criteria); |
318 | return Find(criteria); |
|
319 | } |
319 | } |
|
320 | |
320 | |
|
321 | #endregion |
321 | #endregion FindPreferred |
|
322 | |
322 | |
|
323 | #region DefaultSort |
323 | #region DefaultSort |
|
324 | |
324 | |
|
325 | /// <summary> |
325 | /// <summary> |
|
326 | /// Sorts the list comparing by weight in |
326 | /// Sorts the list comparing by weight in |
|
327 | /// descending order |
327 | /// descending order |
|
328 | /// </summary> |
328 | /// </summary> |
|
329 | public void DefaultSort() |
329 | public void DefaultSort() |
|
330 | { |
330 | { |
|
331 | Sort(QValue.CompareByWeightDesc); |
331 | Sort(QValue.CompareByWeightDesc); |
|
332 | } |
332 | } |
|
333 | |
333 | |
|
334 | #endregion |
334 | #endregion DefaultSort |
|
335 | |
335 | |
|
336 | #region applyAutoSort |
336 | #region applyAutoSort |
|
337 | |
337 | |
|
338 | /// <summary> |
338 | /// <summary> |
|
339 | /// Applies the default sorting method if |
339 | /// Applies the default sorting method if |
|
340 | /// the autosort field is currently enabled |
340 | /// the autosort field is currently enabled |
|
341 | /// </summary> |
341 | /// </summary> |
|
342 | private void applyAutoSort() |
342 | private void applyAutoSort() |
|
343 | { |
343 | { |
|
344 | if (AutoSort) |
344 | if (AutoSort) |
|
345 | DefaultSort(); |
345 | DefaultSort(); |
|
346 | } |
346 | } |
|
347 | |
347 | |
|
348 | #endregion |
348 | #endregion applyAutoSort |
|
349 | |
349 | |
|
350 | #region isCandidate |
350 | #region isCandidate |
|
351 | |
351 | |
|
352 | /// <summary> |
352 | /// <summary> |
|
353 | /// Determines if the given item contained within the applied array |
353 | /// Determines if the given item contained within the applied array |
|
354 | /// (case-insensitive) |
354 | /// (case-insensitive) |
|
355 | /// </summary> |
355 | /// </summary> |
|
356 | /// <param name="item">The string to search for</param> |
356 | /// <param name="item">The string to search for</param> |
|
357 | /// <param name="candidates">The array to search in</param> |
357 | /// <param name="candidates">The array to search in</param> |
|
358 | /// <returns></returns> |
358 | /// <returns></returns> |
|
359 | private static bool isCandidate(string item, params string[] candidates) |
359 | private static bool isCandidate(string item, params string[] candidates) |
|
360 | { |
360 | { |
|
361 | foreach (var candidate in candidates) |
361 | foreach (var candidate in candidates) |
|
362 | { |
362 | { |
|
363 | if (candidate.Equals(item, StringComparison.OrdinalIgnoreCase)) |
363 | if (candidate.Equals(item, StringComparison.OrdinalIgnoreCase)) |
|
364 | return true; |
364 | return true; |
|
365 | } |
365 | } |
|
366 | return false; |
366 | return false; |
|
367 | } |
367 | } |
|
368 | |
368 | |
|
369 | #endregion |
- | ||
370 | |
- | ||
371 | #region Fields |
- | ||
372 | |
- | ||
373 | #endregion |
369 | #endregion isCandidate |
|
374 | |
370 | |
|
375 | #region Constructors |
371 | #region Constructors |
|
376 | |
372 | |
|
377 | /// <summary> |
373 | /// <summary> |
|
378 | /// Creates a new instance of an QValueList list from |
374 | /// Creates a new instance of an QValueList list from |
|
379 | /// the given string of comma delimited values |
375 | /// the given string of comma delimited values |
|
380 | /// </summary> |
376 | /// </summary> |
|
381 | /// <param name="values">The raw string of qvalues to load</param> |
377 | /// <param name="values">The raw string of qvalues to load</param> |
|
382 | public QValueList(string values) |
378 | public QValueList(string values) |
|
383 | : this(null == values ? new string[0] : values.Split(delimiters, StringSplitOptions.RemoveEmptyEntries)) |
379 | : this(null == values ? new string[0] : values.Split(delimiters, StringSplitOptions.RemoveEmptyEntries)) |
|
384 | { |
380 | { |
|
385 | } |
381 | } |
|
386 | |
382 | |
|
387 | /// <summary> |
383 | /// <summary> |
|
388 | /// Creates a new instance of an QValueList from |
384 | /// Creates a new instance of an QValueList from |
|
389 | /// the given string array of qvalues |
385 | /// the given string array of qvalues |
|
390 | /// </summary> |
386 | /// </summary> |
|
391 | /// <param name="values"> |
387 | /// <param name="values"> |
|
392 | /// The array of qvalue strings |
388 | /// The array of qvalue strings |
|
393 | /// i.e. name(;q=[0-9\.]+)? |
389 | /// i.e. name(;q=[0-9\.]+)? |
|
394 | /// </param> |
390 | /// </param> |
|
395 | /// <remarks> |
391 | /// <remarks> |
|
396 | /// Should AcceptWildcard include */* as well? |
392 | /// Should AcceptWildcard include */* as well? |
|
397 | /// What about other wildcard forms? |
393 | /// What about other wildcard forms? |
|
398 | /// </remarks> |
394 | /// </remarks> |
|
399 | public QValueList(string[] values) |
395 | public QValueList(string[] values) |
|
400 | { |
396 | { |
|
401 | var ordinal = -1; |
397 | var ordinal = -1; |
|
402 | foreach (var value in values) |
398 | foreach (var value in values) |
|
403 | { |
399 | { |
|
404 | var qvalue = QValue.Parse(value.Trim(), ++ordinal); |
400 | var qvalue = QValue.Parse(value.Trim(), ++ordinal); |
|
405 | if (qvalue.Name.Equals("*")) // wildcard |
401 | if (qvalue.Name.Equals("*")) // wildcard |
|
406 | AcceptWildcard = qvalue.CanAccept; |
402 | AcceptWildcard = qvalue.CanAccept; |
|
407 | Add(qvalue); |
403 | Add(qvalue); |
|
408 | } |
404 | } |
|
409 | |
405 | |
|
410 | /// this list should be sorted by weight for |
406 | /// this list should be sorted by weight for |
|
411 | /// methods like FindPreferred to work correctly |
407 | /// methods like FindPreferred to work correctly |
|
412 | DefaultSort(); |
408 | DefaultSort(); |
|
413 | AutoSort = true; |
409 | AutoSort = true; |
|
414 | } |
410 | } |
|
415 | |
411 | |
|
416 | #endregion |
412 | #endregion Constructors |
|
417 | |
413 | |
|
418 | #region Properties |
414 | #region Properties |
|
419 | |
415 | |
|
420 | /// <summary> |
416 | /// <summary> |
|
421 | /// Whether or not the wildcarded encoding is available and allowed |
417 | /// Whether or not the wildcarded encoding is available and allowed |
|
422 | /// </summary> |
418 | /// </summary> |
|
423 | public bool AcceptWildcard { get; } |
419 | public bool AcceptWildcard { get; } |
|
424 | |
420 | |
|
425 | /// <summary> |
421 | /// <summary> |
|
426 | /// Whether, after an add operation, the list should be resorted |
422 | /// Whether, after an add operation, the list should be resorted |
|
427 | /// </summary> |
423 | /// </summary> |
|
428 | public bool AutoSort { get; set; } |
424 | public bool AutoSort { get; set; } |
|
429 | |
425 | |
|
430 | /// <summary> |
426 | /// <summary> |
|
431 | /// Synonym for FindPreferred |
427 | /// Synonym for FindPreferred |
|
432 | /// </summary> |
428 | /// </summary> |
|
433 | /// <param name="candidates">The preferred order in which to return an encoding</param> |
429 | /// <param name="candidates">The preferred order in which to return an encoding</param> |
|
434 | /// <returns>An QValue based on weight, or null</returns> |
430 | /// <returns>An QValue based on weight, or null</returns> |
|
435 | public QValue this[params string[] candidates] => FindPreferred(candidates); |
431 | public QValue this[params string[] candidates] => FindPreferred(candidates); |
|
436 | |
432 | |
|
437 | #endregion |
433 | #endregion Properties |
|
438 | } |
- | ||
439 | } |
434 | } |
|
- | 435 | } |
||
440 | |
436 | |
|
441 |
|
- | ||
442 | |
- | ||
443 | |
- | ||
444 | |
- |