#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
}
}