aboutsummaryrefslogtreecommitdiff
path: root/RSSDP/UPnP10DeviceValidator.cs
diff options
context:
space:
mode:
authorLuke Pulverenti <luke.pulverenti@gmail.com>2016-10-29 18:22:20 -0400
committerLuke Pulverenti <luke.pulverenti@gmail.com>2016-10-29 18:22:20 -0400
commitdca78b13411db96366dddfa0d68bb6d36d28ad14 (patch)
tree7d41e670f1cadec0db9e1ed7115e151da891f7ea /RSSDP/UPnP10DeviceValidator.cs
parent597e27d1c6199a40398abb068282711a9cb9db1b (diff)
rework dlna project
Diffstat (limited to 'RSSDP/UPnP10DeviceValidator.cs')
-rw-r--r--RSSDP/UPnP10DeviceValidator.cs194
1 files changed, 194 insertions, 0 deletions
diff --git a/RSSDP/UPnP10DeviceValidator.cs b/RSSDP/UPnP10DeviceValidator.cs
new file mode 100644
index 000000000..f802b7639
--- /dev/null
+++ b/RSSDP/UPnP10DeviceValidator.cs
@@ -0,0 +1,194 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Rssdp.Infrastructure
+{
+ /// <summary>
+ /// Validates a <see cref="SsdpDevice"/> object's properties meet the UPnP 1.0 specification.
+ /// </summary>
+ /// <remarks>
+ /// <para>This is a best effort validation for known rules, it doesn't guarantee 100% compatibility with the specification. Reading the specification yourself is the best way to ensure compatibility.</para>
+ /// </remarks>
+ public class Upnp10DeviceValidator : IUpnpDeviceValidator
+ {
+
+ #region Public Methods
+
+ /// <summary>
+ /// Returns an enumerable set of strings, each one being a description of an invalid property on the specified root device.
+ /// </summary>
+ /// <remarks>
+ /// <para>If no errors are found, an empty (but non-null) enumerable is returned.</para>
+ /// </remarks>
+ /// <param name="device">The <see cref="SsdpRootDevice"/> to validate.</param>
+ /// <exception cref="System.ArgumentNullException">Thrown if the <paramref name="device"/> argument is null.</exception>
+ /// <returns>A non-null enumerable set of strings, empty if there are no validation errors, otherwise each string represents a discrete problem.</returns>
+ public IEnumerable<string> GetValidationErrors(SsdpRootDevice device)
+ {
+ if (device == null) throw new ArgumentNullException("device");
+
+ var retVal = GetValidationErrors((SsdpDevice)device) as IList<string>;
+
+ if (device.Location == null)
+ retVal.Add("Location cannot be null.");
+ else if (!device.Location.IsAbsoluteUri)
+ retVal.Add("Location must be an absolute URL.");
+
+ return retVal;
+ }
+
+ /// <summary>
+ /// Returns an enumerable set of strings, each one being a description of an invalid property on the specified device.
+ /// </summary>
+ /// <remarks>
+ /// <para>If no errors are found, an empty (but non-null) enumerable is returned.</para>
+ /// </remarks>
+ /// <param name="device">The <see cref="SsdpDevice"/> to validate.</param>
+ /// <exception cref="System.ArgumentNullException">Thrown if the <paramref name="device"/> argument is null.</exception>
+ /// <returns>A non-null enumerable set of strings, empty if there are no validation errors, otherwise each string represents a discrete problem.</returns>
+ public IEnumerable<string> GetValidationErrors(SsdpDevice device)
+ {
+ if (device == null) throw new ArgumentNullException("device");
+
+ var retVal = new List<string>();
+
+ if (String.IsNullOrEmpty(device.Uuid))
+ retVal.Add("Uuid is not set.");
+
+ if (!String.IsNullOrEmpty(device.Upc))
+ ValidateUpc(device, retVal);
+
+ if (String.IsNullOrEmpty(device.Udn))
+ retVal.Add("UDN is not set.");
+ else
+ ValidateUdn(device, retVal);
+
+ if (String.IsNullOrEmpty(device.DeviceType))
+ retVal.Add("DeviceType is not set.");
+
+ if (String.IsNullOrEmpty(device.DeviceTypeNamespace))
+ retVal.Add("DeviceTypeNamespace is not set.");
+ else
+ {
+ if (IsOverLength(device.DeviceTypeNamespace, 64))
+ retVal.Add("DeviceTypeNamespace cannot be longer than 64 characters.");
+
+ //if (device.DeviceTypeNamespace.Contains("."))
+ // retVal.Add("Period (.) characters in the DeviceTypeNamespace property must be replaced with hyphens (-).");
+ }
+
+ if (device.DeviceVersion <= 0)
+ retVal.Add("DeviceVersion must be 1 or greater.");
+
+ if (IsOverLength(device.ModelName, 32))
+ retVal.Add("ModelName cannot be longer than 32 characters.");
+
+ if (IsOverLength(device.ModelNumber, 32))
+ retVal.Add("ModelNumber cannot be longer than 32 characters.");
+
+ if (IsOverLength(device.FriendlyName, 64))
+ retVal.Add("FriendlyName cannot be longer than 64 characters.");
+
+ if (IsOverLength(device.Manufacturer, 64))
+ retVal.Add("Manufacturer cannot be longer than 64 characters.");
+
+ if (IsOverLength(device.SerialNumber, 64))
+ retVal.Add("SerialNumber cannot be longer than 64 characters.");
+
+ if (IsOverLength(device.ModelDescription, 128))
+ retVal.Add("ModelDescription cannot be longer than 128 characters.");
+
+ if (String.IsNullOrEmpty(device.FriendlyName))
+ retVal.Add("FriendlyName is required.");
+
+ if (String.IsNullOrEmpty(device.Manufacturer))
+ retVal.Add("Manufacturer is required.");
+
+ if (String.IsNullOrEmpty(device.ModelName))
+ retVal.Add("ModelName is required.");
+
+ if (device.Icons.Any())
+ ValidateIcons(device, retVal);
+
+ ValidateChildDevices(device, retVal);
+
+ return retVal;
+ }
+
+ /// <summary>
+ /// Validates the specified device and throws an <see cref="System.InvalidOperationException"/> if there are any validation errors.
+ /// </summary>
+ /// <param name="device">The <see cref="SsdpDevice"/> to validate.</param>
+ /// <exception cref="System.ArgumentNullException">Thrown if the <paramref name="device"/> argument is null.</exception>
+ /// <exception cref="System.InvalidOperationException">Thrown if the device object does not pass validation.</exception>
+ public void ThrowIfDeviceInvalid(SsdpDevice device)
+ {
+ var errors = this.GetValidationErrors(device);
+ if (errors != null && errors.Any()) throw new InvalidOperationException("Invalid device settings : " + String.Join(Environment.NewLine, errors));
+ }
+
+ #endregion
+
+ #region Private Methods
+
+ private static void ValidateUpc(SsdpDevice device, List<string> retVal)
+ {
+ if (device.Upc.Length != 12)
+ retVal.Add("Upc, if provided, should be 12 digits.");
+
+ foreach (char c in device.Upc)
+ {
+ if (!Char.IsDigit(c))
+ {
+ retVal.Add("Upc, if provided, should contain only digits (numeric characters).");
+ break;
+ }
+ }
+ }
+
+ private static void ValidateUdn(SsdpDevice device, List<string> retVal)
+ {
+ if (!device.Udn.StartsWith("uuid:", StringComparison.OrdinalIgnoreCase))
+ retVal.Add("UDN must begin with uuid:. Correct format is uuid:<uuid>");
+ else if (device.Udn.Substring(5).Trim() != device.Uuid)
+ retVal.Add("UDN incorrect. Correct format is uuid:<uuid>");
+ }
+
+ private static void ValidateIcons(SsdpDevice device, List<string> retVal)
+ {
+ if (device.Icons.Any((di) => di.Url == null))
+ retVal.Add("Device icon is missing URL.");
+
+ if (device.Icons.Any((di) => String.IsNullOrEmpty(di.MimeType)))
+ retVal.Add("Device icon is missing mime type.");
+
+ if (device.Icons.Any((di) => di.Width <= 0 || di.Height <= 0))
+ retVal.Add("Device icon has zero (or negative) height, width or both.");
+
+ if (device.Icons.Any((di) => di.ColorDepth <= 0))
+ retVal.Add("Device icon has zero (or negative) colordepth.");
+ }
+
+ private void ValidateChildDevices(SsdpDevice device, List<string> retVal)
+ {
+ foreach (var childDevice in device.Devices)
+ {
+ foreach (var validationError in this.GetValidationErrors(childDevice))
+ {
+ retVal.Add("Embedded Device : " + childDevice.Uuid + ": " + validationError);
+ }
+ }
+ }
+
+ private static bool IsOverLength(string value, int maxLength)
+ {
+ return !String.IsNullOrEmpty(value) && value.Length > maxLength;
+ }
+
+ #endregion
+
+ }
+}