#region License /* * Ext.cs * IsPredefinedScheme and MaybeUri methods derived from System.Uri.cs * GetStatusDescription method derived from System.Net.HttpListenerResponse.cs * * The MIT License * * Copyright (c) 2010-2013 sta.blockhead * * System.Uri.cs * (C) 2001 Garrett Rooney * (C) 2003 Ian MacLean * (C) 2003 Ben Maurer * Copyright (C) 2003, 2005, 2009 Novell, Inc. (http://www.novell.com) * Copyright (c) 2009 Stephane Delcroix * * System.Net.HttpListenerResponse.cs * Copyright (C) 2003, 2005, 2009 Novell, Inc. (http://www.novell.com) * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #endregion using System; using System.Collections.Generic; using System.Collections.Specialized; using System.IO; using System.IO.Compression; using System.Linq; using System.Net.Sockets; using System.Text; using WebSocketSharp.Net; using WebSocketSharp.Net.WebSockets; namespace WebSocketSharp { /// /// Provides a set of static methods for the websocket-sharp. /// public static class Ext { #region Private Const Fields private const string _tspecials = "()<>@,;:\\\"/[]?={} \t"; #endregion #region Private Methods private static byte[] compress(this byte[] value) { if (value.LongLength == 0) //return new Byte[] { 0x00, 0x00, 0x00, 0xff, 0xff }; return value; using (var input = new MemoryStream(value)) { return input.compressToArray(); } } private static MemoryStream compress(this Stream stream) { var output = new MemoryStream(); if (stream.Length == 0) return output; stream.Position = 0; using (var ds = new DeflateStream(output, CompressionMode.Compress, true)) { stream.CopyTo(ds); ds.Close(); // "BFINAL" set to 1. output.Position = 0; return output; } } private static byte[] compressToArray(this Stream stream) { using (var comp = stream.compress()) { comp.Close(); return comp.ToArray(); } } private static byte[] decompress(this byte[] value) { if (value.LongLength == 0) return value; using (var input = new MemoryStream(value)) { return input.decompressToArray(); } } private static MemoryStream decompress(this Stream stream) { var output = new MemoryStream(); if (stream.Length == 0) return output; stream.Position = 0; using (var ds = new DeflateStream(stream, CompressionMode.Decompress, true)) { ds.CopyTo(output, true); return output; } } private static byte[] decompressToArray(this Stream stream) { using (var decomp = stream.decompress()) { decomp.Close(); return decomp.ToArray(); } } private static void times(this ulong n, Action act) { for (ulong i = 0; i < n; i++) act(); } #endregion #region Internal Methods internal static byte[] Compress(this byte[] value, CompressionMethod method) { return method == CompressionMethod.DEFLATE ? value.compress() : value; } internal static Stream Compress(this Stream stream, CompressionMethod method) { return method == CompressionMethod.DEFLATE ? stream.compress() : stream; } internal static byte[] CompressToArray(this Stream stream, CompressionMethod method) { return method == CompressionMethod.DEFLATE ? stream.compressToArray() : stream.ToByteArray(); } internal static void CopyTo(this Stream src, Stream dest) { src.CopyTo(dest, false); } internal static void CopyTo(this Stream src, Stream dest, bool setDefaultPosition) { int readLen; int bufferLen = 256; var buffer = new byte[bufferLen]; while ((readLen = src.Read(buffer, 0, bufferLen)) > 0) { dest.Write(buffer, 0, readLen); } if (setDefaultPosition) dest.Position = 0; } internal static byte[] Decompress(this byte[] value, CompressionMethod method) { return method == CompressionMethod.DEFLATE ? value.decompress() : value; } internal static Stream Decompress(this Stream stream, CompressionMethod method) { return method == CompressionMethod.DEFLATE ? stream.decompress() : stream; } internal static byte[] DecompressToArray(this Stream stream, CompressionMethod method) { return method == CompressionMethod.DEFLATE ? stream.decompressToArray() : stream.ToByteArray(); } internal static string GetNameInternal(this string nameAndValue, string separator) { int i = nameAndValue.IndexOf(separator); return i > 0 ? nameAndValue.Substring(0, i).Trim() : null; } internal static string GetMessage(this CloseStatusCode code) { if (code == CloseStatusCode.ABNORMAL) return "What we've got here is a failure to communicate in the WebSocket protocol."; if (code == CloseStatusCode.TOO_BIG) return String.Format( "The size of received payload data is bigger than the allowable value ({0} bytes).", PayloadData.MaxLength); return String.Empty; } internal static string GetValueInternal(this string nameAndValue, string separator) { int i = nameAndValue.IndexOf(separator); return i >= 0 && i < nameAndValue.Length - 1 ? nameAndValue.Substring(i + 1).Trim() : null; } internal static bool IsText(this string value) { int len = value.Length; for (int i = 0; i < len; i++) { char c = value[i]; if (c < 0x20 && !"\r\n\t".Contains(c)) return false; if (c == 0x7f) return false; if (c == '\n' && ++i < len) { c = value[i]; if (!" \t".Contains(c)) return false; } } return true; } internal static bool IsToken(this string value) { foreach (char c in value) if (c < 0x20 || c >= 0x7f || _tspecials.Contains(c)) return false; return true; } internal static string Quote(this string value) { return value.IsToken() ? value : String.Format("\"{0}\"", value.Replace("\"", "\\\"")); } internal static string RemovePrefix(this string value, params string[] prefixes) { int i = 0; foreach (var prefix in prefixes) { if (value.StartsWith(prefix)) { i = prefix.Length; break; } } return i > 0 ? value.Substring(i) : value; } internal static IEnumerable SplitHeaderValue(this string value, params char[] separator) { var separators = new string(separator); var buffer = new StringBuilder(64); int len = value.Length; bool quoted = false; bool escaped = false; for (int i = 0; i < len; i++) { char c = value[i]; if (c == '"') { if (escaped) escaped = !escaped; else quoted = !quoted; } else if (c == '\\') { if (i < len - 1 && value[i + 1] == '"') escaped = true; } else if (separators.Contains(c)) { if (!quoted) { yield return buffer.ToString(); buffer.Length = 0; continue; } } else { } buffer.Append(c); } if (buffer.Length > 0) yield return buffer.ToString(); } internal static byte[] ToByteArray(this Stream stream) { using (var output = new MemoryStream()) { stream.Position = 0; stream.CopyTo(output); output.Close(); return output.ToArray(); } } internal static void WriteBytes(this Stream stream, byte[] value) { using (var input = new MemoryStream(value)) { input.CopyTo(stream); } } #endregion #region Public Methods /// /// Accepts a WebSocket connection by the . /// /// /// A that contains a WebSocket connection. /// /// /// A that provides a TCP connection to accept a WebSocket connection. /// /// /// A that indicates a secure connection or not. (true indicates a secure connection.) /// /// /// is . /// public static TcpListenerWebSocketContext AcceptWebSocket(this TcpListener listener, bool secure) { if (listener.IsNull()) throw new ArgumentNullException("listener"); var client = listener.AcceptTcpClient(); return new TcpListenerWebSocketContext(client, secure); } /// /// Accepts a WebSocket connection asynchronously by the . /// /// /// A that provides a TCP connection to accept a WebSocket connection. /// /// /// A that indicates a secure connection or not. (true indicates a secure connection.) /// /// /// An Action<TcpListenerWebSocketContext> delegate that contains the method(s) that is called when an asynchronous operation completes. /// /// /// is . /// public static void AcceptWebSocketAsync(this TcpListener listener, bool secure, Action completed) { if (listener.IsNull()) throw new ArgumentNullException("listener"); AsyncCallback callback = (ar) => { var client = listener.EndAcceptTcpClient(ar); var context = new TcpListenerWebSocketContext(client, secure); completed(context); }; listener.BeginAcceptTcpClient(callback, null); } /// /// Determines whether the specified contains any of characters /// in the specified array of . /// /// /// true if contains any of ; otherwise, false. /// /// /// A to test. /// /// /// An array of that contains characters to find. /// public static bool Contains(this string str, params char[] chars) { return str.IsNullOrEmpty() ? false : chars.Length == 0 ? true : str.IndexOfAny(chars) != -1; } /// /// Emit the specified delegate if is not . /// /// /// An to emit. /// /// /// An that emits the . /// /// /// An that contains no event data. /// public static void Emit( this EventHandler eventHandler, object sender, EventArgs e) { if (!eventHandler.IsNull()) eventHandler(sender, e); } /// /// Emit the specified EventHandler<TEventArgs> delegate if is not . /// /// /// An EventHandler<TEventArgs> to emit. /// /// /// An that emits the . /// /// /// A TEventArgs that contains the event data. /// /// /// The type of the event data generated by the event. /// public static void Emit( this EventHandler eventHandler, object sender, TEventArgs e) where TEventArgs : EventArgs { if (!eventHandler.IsNull()) eventHandler(sender, e); } /// /// Determines whether the specified equals the specified as . /// And save this specified as to the specified List<byte>. /// /// /// true if the parameter equals the parameter as ; otherwise, false. /// /// /// An to compare. /// /// /// A to compare. /// /// /// A List<byte> to save the as . /// /// /// Is thrown when the parameter passed to a method is invalid because it is outside the allowable range of values as . /// public static bool EqualsAndSaveTo(this int value, char c, List dest) { if (value < 0 || value > 255) throw new ArgumentOutOfRangeException("value"); var b = (byte)value; dest.Add(b); return b == Convert.ToByte(c); } /// /// Determines whether the entry with the specified key exists in the specified . /// /// /// true if the entry with the exists in the ; otherwise, false. /// /// /// A that contains the entries. /// /// /// A that contains the key of the entry to find. /// public static bool Exists(this NameValueCollection collection, string name) { return collection.IsNull() ? false : !collection[name].IsNull(); } /// /// Determines whether the entry with the specified both key and value exists in the specified . /// /// /// true if the entry with the both and exists in the ; otherwise, false. /// /// /// A that contains the entries. /// /// /// A that contains the key of the entry to find. /// /// /// A that contains the value of the entry to find. /// public static bool Exists(this NameValueCollection collection, string name, string value) { if (collection.IsNull()) return false; var values = collection[name]; if (values.IsNull()) return false; foreach (string v in values.Split(',')) if (String.Compare(v.Trim(), value, true) == 0) return true; return false; } /// /// Gets the absolute path from the specified . /// /// /// A that contains the absolute path if got successfully; otherwise, . /// /// /// A that contains the URI to get the absolute path from. /// public static string GetAbsolutePath(this Uri uri) { if (uri.IsNull()) return null; if (uri.IsAbsoluteUri) return uri.AbsolutePath; var uriString = uri.OriginalString; var i = uriString.IndexOf('/'); if (i != 0) return null; i = uriString.IndexOfAny(new []{'?', '#'}); return i > 0 ? uriString.Substring(0, i) : uriString; } /// /// Gets the collection of cookies from the specified . /// /// /// A that receives a collection of the HTTP Cookies. /// /// /// A that contains a collection of the HTTP Headers. /// /// /// true if gets from the response ; /// from the request , false. /// public static CookieCollection GetCookies(this NameValueCollection headers, bool response) { var name = response ? "Set-Cookie" : "Cookie"; if (headers.IsNull() || !headers.Exists(name)) return new CookieCollection(); return CookieCollection.Parse(headers[name], response); } /// /// Gets the description of the HTTP status code using the specified . /// /// /// A that contains the description of the HTTP status code. /// /// /// One of values that contains an HTTP status code. /// public static string GetDescription(this HttpStatusCode code) { return ((int)code).GetStatusDescription(); } /// /// Gets the name from the specified that contains a pair of name and value are separated by a separator string. /// /// /// A that contains the name if any; otherwise, null. /// /// /// A that contains a pair of name and value are separated by a separator string. /// /// /// A that contains a separator string. /// public static string GetName(this string nameAndValue, string separator) { return !nameAndValue.IsNullOrEmpty() && !separator.IsNullOrEmpty() ? nameAndValue.GetNameInternal(separator) : null; } /// /// Gets the name and value from the specified that contains a pair of name and value are separated by a separator string. /// /// /// A KeyValuePair<string, string> that contains the name and value if any. /// /// /// A that contains a pair of name and value are separated by a separator string. /// /// /// A that contains a separator string. /// public static KeyValuePair GetNameAndValue(this string nameAndValue, string separator) { var name = nameAndValue.GetName(separator); var value = nameAndValue.GetValue(separator); return !name.IsNull() ? new KeyValuePair(name, value) : new KeyValuePair(null, null); } /// /// Gets the description of the HTTP status code using the specified . /// /// /// A that contains the description of the HTTP status code. /// /// /// An that contains an HTTP status code. /// public static string GetStatusDescription(this int code) { switch (code) { case 100: return "Continue"; case 101: return "Switching Protocols"; case 102: return "Processing"; case 200: return "OK"; case 201: return "Created"; case 202: return "Accepted"; case 203: return "Non-Authoritative Information"; case 204: return "No Content"; case 205: return "Reset Content"; case 206: return "Partial Content"; case 207: return "Multi-Status"; case 300: return "Multiple Choices"; case 301: return "Moved Permanently"; case 302: return "Found"; case 303: return "See Other"; case 304: return "Not Modified"; case 305: return "Use Proxy"; case 307: return "Temporary Redirect"; case 400: return "Bad Request"; case 401: return "Unauthorized"; case 402: return "Payment Required"; case 403: return "Forbidden"; case 404: return "Not Found"; case 405: return "Method Not Allowed"; case 406: return "Not Acceptable"; case 407: return "Proxy Authentication Required"; case 408: return "Request Timeout"; case 409: return "Conflict"; case 410: return "Gone"; case 411: return "Length Required"; case 412: return "Precondition Failed"; case 413: return "Request Entity Too Large"; case 414: return "Request-Uri Too Long"; case 415: return "Unsupported Media Type"; case 416: return "Requested Range Not Satisfiable"; case 417: return "Expectation Failed"; case 422: return "Unprocessable Entity"; case 423: return "Locked"; case 424: return "Failed Dependency"; case 500: return "Internal Server Error"; case 501: return "Not Implemented"; case 502: return "Bad Gateway"; case 503: return "Service Unavailable"; case 504: return "Gateway Timeout"; case 505: return "Http Version Not Supported"; case 507: return "Insufficient Storage"; } return String.Empty; } /// /// Gets the value from the specified that contains a pair of name and value are separated by a separator string. /// /// /// A that contains the value if any; otherwise, null. /// /// /// A that contains a pair of name and value are separated by a separator string. /// /// /// A that contains a separator string. /// public static string GetValue(this string nameAndValue, string separator) { return !nameAndValue.IsNullOrEmpty() && !separator.IsNullOrEmpty() ? nameAndValue.GetValueInternal(separator) : null; } /// /// Determines whether the specified is in the allowable range of /// the WebSocket close status code. /// /// /// Not allowable ranges are the followings. /// /// /// /// Numbers in the range 0-999 are not used. /// /// /// /// /// Numbers which are greater than 4999 are out of the reserved close status code ranges. /// /// /// /// /// /// true if is in the allowable range of the WebSocket close status code; otherwise, false. /// /// /// A to test. /// public static bool IsCloseStatusCode(this ushort code) { return code < 1000 ? false : code > 4999 ? false : true; } /// /// Determines whether the specified is empty. /// /// /// true if is empty; otherwise, false. /// /// /// A to test. /// public static bool IsEmpty(this string value) { return value.Length == 0; } /// /// Determines whether the specified is enclosed in the specified . /// /// /// true if is enclosed in ; otherwise, false. /// /// /// A to test. /// /// /// A that contains character to find. /// public static bool IsEnclosedIn(this string str, char c) { return str.IsNullOrEmpty() ? false : str[0] == c && str[str.Length - 1] == c; } /// /// Determines whether the specified is host (this computer architecture) byte order. /// /// /// true if the parameter is host byte order; otherwise, false. /// /// /// A to test. /// public static bool IsHostOrder(this ByteOrder order) { // true : !(true ^ true) or !(false ^ false) // false: !(true ^ false) or !(false ^ true) return !(BitConverter.IsLittleEndian ^ (order == ByteOrder.LITTLE)); } /// /// Determines whether the specified represents a local IP address. /// /// /// true if represents a local IP address; otherwise, false. /// /// /// A to test. /// /// /// is . /// public static bool IsLocal(this System.Net.IPAddress address) { if (address.IsNull()) throw new ArgumentNullException("address"); if (System.Net.IPAddress.IsLoopback(address)) return true; var host = System.Net.Dns.GetHostName(); var addrs = System.Net.Dns.GetHostAddresses(host); foreach (var addr in addrs) if (address.Equals(addr)) return true; return false; } /// /// Determines whether the specified object is . /// /// /// true if is ; otherwise, false. /// /// /// An object to test. /// /// /// The type of parameter. /// public static bool IsNull(this T obj) where T : class { return obj == null; } /// /// Determines whether the specified object is . /// And invokes the specified delegate if the specified object is . /// /// /// true if the parameter is ; otherwise, false. /// /// /// A class to test. /// /// /// An delegate that contains the method(s) called if the is . /// /// /// The type of the parameter. /// public static bool IsNullDo(this T obj, Action act) where T : class { if (obj.IsNull()) { act(); return true; } return false; } /// /// Determines whether the specified is or empty. /// /// /// true if the parameter is or empty; otherwise, false. /// /// /// A to test. /// public static bool IsNullOrEmpty(this string value) { return value.IsNull() || value.IsEmpty(); } /// /// Determines whether the specified is predefined scheme. /// /// /// true if the parameter is the predefined scheme; otherwise, false. /// /// /// A to test. /// public static bool IsPredefinedScheme(this string scheme) { if (scheme.IsNull() && scheme.Length < 2) return false; char c = scheme[0]; if (c == 'h') return (scheme == "http" || scheme == "https"); if (c == 'f') return (scheme == "file" || scheme == "ftp"); if (c == 'w') return (scheme == "ws" || scheme == "wss"); if (c == 'n') { c = scheme[1]; if (c == 'e') return (scheme == "news" || scheme == "net.pipe" || scheme == "net.tcp"); if (scheme == "nntp") return true; return false; } if ((c == 'g' && scheme == "gopher") || (c == 'm' && scheme == "mailto")) return true; return false; } /// /// Determines whether the specified is the HTTP Upgrade request /// to switch to the specified . /// /// /// true if the specified is the HTTP Upgrade request /// to switch to the specified ; otherwise, false. /// /// /// A that contains an HTTP request information. /// /// /// A that contains a protocol name. /// /// /// /// is . /// /// /// -or- /// /// /// is . /// /// /// /// is . /// public static bool IsUpgradeTo(this HttpListenerRequest request, string protocol) { if (request.IsNull()) throw new ArgumentNullException("request"); if (protocol.IsNull()) throw new ArgumentNullException("protocol"); if (protocol.IsEmpty()) throw new ArgumentException("Must not be empty.", "protocol"); if (!request.Headers.Exists("Upgrade", protocol)) return false; if (!request.Headers.Exists("Connection", "Upgrade")) return false; return true; } /// /// Determines whether the specified is valid absolute path. /// /// /// true if the parameter is valid absolute path; otherwise, false. /// /// /// A to test. /// /// /// A that receives a message if the is invalid. /// public static bool IsValidAbsolutePath(this string absPath, out string message) { if (absPath.IsNullOrEmpty()) { message = "Must not be null or empty."; return false; } var i = absPath.IndexOf('/'); if (i != 0) { message = "Not absolute path: " + absPath; return false; } i = absPath.IndexOfAny(new []{'?', '#'}); if (i != -1) { message = "Must not contain either or both query and fragment components: " + absPath; return false; } message = String.Empty; return true; } /// /// Determines whether the specified is a URI string. /// /// /// true if the parameter is maybe a URI string; otherwise, false. /// /// /// A to test. /// public static bool MaybeUri(this string uriString) { if (uriString.IsNullOrEmpty()) return false; int p = uriString.IndexOf(':'); if (p == -1) return false; if (p >= 10) return false; return uriString.Substring(0, p).IsPredefinedScheme(); } /// /// Determines whether two specified objects don't have the same value. /// /// /// true if the value of parameter isn't the same as the value of parameter; otherwise, false. /// /// /// The first to compare. /// /// /// The second to compare. /// /// /// A that indicates a case-sensitive or insensitive comparison. (true indicates a case-insensitive comparison.) /// public static bool NotEqual(this string expected, string actual, bool ignoreCase) { return String.Compare(expected, actual, ignoreCase) != 0 ? true : false; } /// /// Reads a block of bytes from the specified stream and returns the read data in an array of . /// /// /// An array of that receives the read data. /// /// /// A that contains the data to read. /// /// /// An that contains the number of bytes to read. /// public static byte[] ReadBytes(this Stream stream, int length) { if (stream.IsNull() || length <= 0) return new byte[]{}; var buffer = new byte[length]; var readLen = stream.Read(buffer, 0, length); return readLen == length ? buffer : readLen > 0 ? buffer.SubArray(0, readLen) : new byte[]{}; } /// /// Reads a block of bytes from the specified stream and returns the read data in an array of . /// /// /// An array of that receives the read data. /// /// /// A that contains the data to read. /// /// /// A that contains the number of bytes to read. /// public static byte[] ReadBytes(this Stream stream, long length) { return stream.ReadBytes(length, 1024); } /// /// Reads a block of bytes from the specified stream and returns the read data in an array of . /// /// /// An array of that receives the read data. /// /// /// A that contains the data to read. /// /// /// A that contains the number of bytes to read. /// /// /// An that contains the buffer size in bytes of each internal read. /// public static byte[] ReadBytes(this Stream stream, long length, int bufferLength) { if (stream.IsNull() || length <= 0) return new byte[]{}; if (bufferLength <= 0) bufferLength = 1024; var count = length / bufferLength; var rem = length % bufferLength; var readData = new List(); var readBuffer = new byte[bufferLength]; long readLen = 0; var tmpLen = 0; Action read = (buffer) => { tmpLen = stream.Read(buffer, 0, buffer.Length); if (tmpLen > 0) { readLen += tmpLen; readData.AddRange(buffer.SubArray(0, tmpLen)); } }; count.Times(() => { read(readBuffer); }); if (rem > 0) read(new byte[rem]); return readLen > 0 ? readData.ToArray() : new byte[]{}; } /// /// Retrieves a sub-array from the specified . A sub-array starts at the specified element position. /// /// /// An array of T that receives a sub-array, or an empty array of T if any problems with the parameters. /// /// /// An array of T that contains the data to retrieve a sub-array. /// /// /// An that contains the zero-based starting position of a sub-array in the . /// /// /// An that contains the number of elements to retrieve a sub-array. /// /// /// The type of elements in the . /// public static T[] SubArray(this T[] array, int startIndex, int length) { if (array.IsNull() || array.Length == 0) return new T[]{}; if (startIndex < 0 || length <= 0) return new T[]{}; if (startIndex + length > array.Length) return new T[]{}; if (startIndex == 0 && array.Length == length) return array; T[] subArray = new T[length]; Array.Copy(array, startIndex, subArray, 0, length); return subArray; } /// /// Executes the specified delegate times. /// /// /// An is the number of times to execute. /// /// /// An delegate that references the method(s) to execute. /// public static void Times(this int n, Action act) { if (n > 0 && !act.IsNull()) ((ulong)n).times(act); } /// /// Executes the specified delegate times. /// /// /// A is the number of times to execute. /// /// /// An delegate that references the method(s) to execute. /// public static void Times(this long n, Action act) { if (n > 0 && !act.IsNull()) ((ulong)n).times(act); } /// /// Executes the specified delegate times. /// /// /// A is the number of times to execute. /// /// /// An delegate that references the method(s) to execute. /// public static void Times(this uint n, Action act) { if (n > 0 && !act.IsNull()) ((ulong)n).times(act); } /// /// Executes the specified delegate times. /// /// /// A is the number of times to execute. /// /// /// An delegate that references the method(s) to execute. /// public static void Times(this ulong n, Action act) { if (n > 0 && !act.IsNull()) n.times(act); } /// /// Executes the specified Action<int> delegate times. /// /// /// An is the number of times to execute. /// /// /// An Action<int> delegate that references the method(s) to execute. /// An parameter to pass to the method(s) is the zero-based count of iteration. /// public static void Times(this int n, Action act) { if (n > 0 && !act.IsNull()) for (int i = 0; i < n; i++) act(i); } /// /// Executes the specified Action<long> delegate times. /// /// /// A is the number of times to execute. /// /// /// An Action<long> delegate that references the method(s) to execute. /// A parameter to pass to the method(s) is the zero-based count of iteration. /// public static void Times(this long n, Action act) { if (n > 0 && !act.IsNull()) for (long i = 0; i < n; i++) act(i); } /// /// Executes the specified Action<uint> delegate times. /// /// /// A is the number of times to execute. /// /// /// An Action<uint> delegate that references the method(s) to execute. /// A parameter to pass to the method(s) is the zero-based count of iteration. /// public static void Times(this uint n, Action act) { if (n > 0 && !act.IsNull()) for (uint i = 0; i < n; i++) act(i); } /// /// Executes the specified Action<ulong> delegate times. /// /// /// A is the number of times to execute. /// /// /// An Action<ulong> delegate that references the method(s) to execute. /// A parameter to pass to this method(s) is the zero-based count of iteration. /// public static void Times(this ulong n, Action act) { if (n > 0 && !act.IsNull()) for (ulong i = 0; i < n; i++) act(i); } /// /// Converts the specified array of to the specified type data. /// /// /// A T converted from the , or a default value of T /// if the is an empty array of /// or if the types of T aren't the , , , /// , , , , /// , , . /// /// /// An array of to convert. /// /// /// A that indicates the byte order of the . /// /// /// The type of the return value. The T must be a value type. /// /// /// Is thrown when the parameter passed to a method is invalid because it is . /// public static T To(this byte[] src, ByteOrder srcOrder) where T : struct { if (src.IsNull()) throw new ArgumentNullException("src"); if (src.Length == 0) return default(T); var type = typeof(T); var buffer = src.ToHostOrder(srcOrder); if (type == typeof(Boolean)) return (T)(object)BitConverter.ToBoolean(buffer, 0); if (type == typeof(Char)) return (T)(object)BitConverter.ToChar(buffer, 0); if (type == typeof(Double)) return (T)(object)BitConverter.ToDouble(buffer, 0); if (type == typeof(Int16)) return (T)(object)BitConverter.ToInt16(buffer, 0); if (type == typeof(Int32)) return (T)(object)BitConverter.ToInt32(buffer, 0); if (type == typeof(Int64)) return (T)(object)BitConverter.ToInt64(buffer, 0); if (type == typeof(Single)) return (T)(object)BitConverter.ToSingle(buffer, 0); if (type == typeof(UInt16)) return (T)(object)BitConverter.ToUInt16(buffer, 0); if (type == typeof(UInt32)) return (T)(object)BitConverter.ToUInt32(buffer, 0); if (type == typeof(UInt64)) return (T)(object)BitConverter.ToUInt64(buffer, 0); return default(T); } /// /// Converts the specified data to an array of . /// /// /// An array of converted from the . /// /// /// A T to convert. /// /// /// A that indicates the byte order of the return. /// /// /// The type of the . The T must be a value type. /// public static byte[] ToByteArray(this T value, ByteOrder order) where T : struct { var type = typeof(T); byte[] buffer; if (type == typeof(Boolean)) { buffer = BitConverter.GetBytes((Boolean)(object)value); } else if (type == typeof(Char)) { buffer = BitConverter.GetBytes((Char)(object)value); } else if (type == typeof(Double)) { buffer = BitConverter.GetBytes((Double)(object)value); } else if (type == typeof(Int16)) { buffer = BitConverter.GetBytes((Int16)(object)value); } else if (type == typeof(Int32)) { buffer = BitConverter.GetBytes((Int32)(object)value); } else if (type == typeof(Int64)) { buffer = BitConverter.GetBytes((Int64)(object)value); } else if (type == typeof(Single)) { buffer = BitConverter.GetBytes((Single)(object)value); } else if (type == typeof(UInt16)) { buffer = BitConverter.GetBytes((UInt16)(object)value); } else if (type == typeof(UInt32)) { buffer = BitConverter.GetBytes((UInt32)(object)value); } else if (type == typeof(UInt64)) { buffer = BitConverter.GetBytes((UInt64)(object)value); } else { buffer = new byte[]{}; } return buffer.Length == 0 || order.IsHostOrder() ? buffer : buffer.Reverse().ToArray(); } /// /// Converts the order of the specified array of to the host byte order. /// /// /// An array of converted from the . /// /// /// An array of to convert. /// /// /// A that indicates the byte order of the . /// /// /// Is thrown when the parameter passed to a method is invalid because it is . /// public static byte[] ToHostOrder(this byte[] src, ByteOrder srcOrder) { if (src.IsNull()) throw new ArgumentNullException("src"); return src.Length == 0 || srcOrder.IsHostOrder() ? src : src.Reverse().ToArray(); } /// /// Converts the specified array to a concatenated the specified separator string /// between each element of this array. /// /// /// A converted from the parameter, or a /// if the length of the is zero. /// /// /// An array of T to convert. /// /// /// A that contains a separator string. /// /// /// The type of elements in the . /// /// /// Is thrown when the parameter passed to a method is invalid because it is . /// public static string ToString(this T[] array, string separator) { if (array.IsNull()) throw new ArgumentNullException("array"); var len = array.Length; if (len == 0) return String.Empty; if (separator.IsNull()) separator = String.Empty; var sb = new StringBuilder(); (len - 1).Times(i => sb.AppendFormat("{0}{1}", array[i].ToString(), separator) ); sb.Append(array[len - 1].ToString()); return sb.ToString(); } /// /// Converts the specified to a object. /// /// /// A converted from the parameter, or /// if the is or . /// /// /// A to convert. /// public static Uri ToUri(this string uriString) { return uriString.IsNullOrEmpty() ? null : uriString.MaybeUri() ? new Uri(uriString) : new Uri(uriString, UriKind.Relative); } /// /// Tries to create a new WebSocket using the specified . /// /// /// true if the WebSocket was successfully created; otherwise, false. /// /// /// A that contains a WebSocket URI. /// /// /// When this method returns, contains a created WebSocket if the parameter is valid WebSocket URI; otherwise, . /// /// /// When this method returns, contains a error message if the parameter is invalid WebSocket URI; otherwise, String.Empty. /// /// /// Is thrown when the parameter passed to a method is invalid because it is . /// public static bool TryCreateWebSocketUri(this string uriString, out Uri result, out string message) { if (uriString.IsNull()) throw new ArgumentNullException("uriString"); result = null; if (uriString.IsEmpty()) { message = "Must not be empty."; return false; } var uri = uriString.ToUri(); if (!uri.IsAbsoluteUri) { message = "Not absolute URI: " + uriString; return false; } var scheme = uri.Scheme; if (scheme != "ws" && scheme != "wss") { message = "Unsupported scheme: " + scheme; return false; } var fragment = uri.Fragment; if (!String.IsNullOrEmpty(fragment)) { message = "Must not contain the fragment component: " + uriString; return false; } var port = uri.Port; if (port > 0) { if ((scheme == "ws" && port == 443) || (scheme == "wss" && port == 80)) { message = String.Format( "Invalid pair of scheme and port: {0}, {1}", scheme, port); return false; } } else { port = scheme == "ws" ? 80 : 443; var url = String.Format("{0}://{1}:{2}{3}", scheme, uri.Host, port, uri.PathAndQuery); uri = url.ToUri(); } result = uri; message = String.Empty; return true; } /// /// URL-decodes the specified . /// /// /// A that receives a decoded string, or the parameter /// if the is or . /// /// /// A to decode. /// public static string UrlDecode(this string s) { return s.IsNullOrEmpty() ? s : HttpUtility.UrlDecode(s); } /// /// URL-encodes the specified . /// /// /// A that receives a encoded string, or the parameter /// if the is or . /// /// /// A to encode. /// public static string UrlEncode(this string s) { return s.IsNullOrEmpty() ? s : HttpUtility.UrlEncode(s); } /// /// Writes the specified content data using the specified . /// /// /// A that contains a network stream to write a content data. /// /// /// An array of that contains a content data to write. /// /// /// Is thrown when the parameter passed to a method is invalid because it is . /// public static void WriteContent(this HttpListenerResponse response, byte[] content) { if (response.IsNull()) throw new ArgumentNullException("response"); if (content.IsNull() || content.Length == 0) return; var output = response.OutputStream; response.ContentLength64 = content.Length; output.Write(content, 0, content.Length); output.Close(); } #endregion } }