private static void ParseDevice(String XML, int startLine, ref UPnPDevice RetVal) { string TempString; UPnPService service; int embeddedLine; DText p = new DText(); TextReader MyString = new StringReader(XML); XmlTextReader XMLDoc = new XmlTextReader(MyString); try { XMLDoc.Read(); XMLDoc.MoveToContent(); if (XMLDoc.LocalName == "device") { if (XMLDoc.AttributeCount > 0) { for (int ax = 0; ax < XMLDoc.AttributeCount; ++ax) { XMLDoc.MoveToAttribute(ax); if (XMLDoc.LocalName == "MaxVersion") { RetVal.SetVersion(XMLDoc.Value); } } XMLDoc.MoveToContent(); XMLDoc.Read(); } else { XMLDoc.Read(); XMLDoc.MoveToContent(); } while (XMLDoc.LocalName != "device" && !XMLDoc.EOF) { switch (XMLDoc.LocalName) { case "deviceList": embeddedLine = XMLDoc.LineNumber; ParseDeviceList(XMLDoc.ReadOuterXml(), startLine + embeddedLine - 1, ref RetVal); break; case "URLBase": // Here, tport is a hack to make Windows Home Server visible. WHS does no set the port in the BaseURL and so, you need to keep it from the SSDP message. int tport = 80; if (RetVal.BaseURL != null) tport = RetVal.BaseURL.Port; RetVal.BaseURL = new Uri(XMLDoc.ReadString()); if (RetVal.BaseURL.Port == 80 && RetVal.BaseURL.Port != tport) RetVal.BaseURL = new Uri(RetVal.BaseURL.Scheme + "://" + RetVal.BaseURL.Host + ":" + tport + RetVal.BaseURL.AbsolutePath); break; case "deviceType": RetVal.DeviceURN = XMLDoc.ReadString(); break; case "friendlyName": RetVal.FriendlyName = XMLDoc.ReadString(); break; case "manufacturer": RetVal.Manufacturer = XMLDoc.ReadString(); break; case "manufacturerURL": RetVal.ManufacturerURL = XMLDoc.ReadString(); break; case "modelDescription": RetVal.ModelDescription = XMLDoc.ReadString(); break; case "modelName": RetVal.ModelName = XMLDoc.ReadString(); break; case "modelNumber": RetVal.ModelNumber = XMLDoc.ReadString(); break; case "modelURL": try { string u = XMLDoc.ReadString(); if (Uri.TryCreate(u, UriKind.Absolute, out RetVal.ModelURL) == false) { Uri.TryCreate("http://" + u, UriKind.Absolute, out RetVal.ModelURL); } } catch (Exception ex) { OpenSource.Utilities.EventLogger.Log(ex); } break; case "serialNumber": RetVal.SerialNumber = XMLDoc.ReadString(); break; case "UDN": TempString = XMLDoc.ReadString(); RetVal.UniqueDeviceName = TempString.Substring(5); break; case "UPC": RetVal.ProductCode = XMLDoc.ReadString(); break; case "presentationURL": RetVal.HasPresentation = true; RetVal.PresentationURL = XMLDoc.ReadString(); break; case "serviceList": if (XMLDoc.IsEmptyElement) break; XMLDoc.Read(); XMLDoc.MoveToContent(); while (XMLDoc.LocalName != "serviceList") { if (XMLDoc.LocalName == "service") { embeddedLine = XMLDoc.LineNumber; service = UPnPService.Parse(XMLDoc.ReadOuterXml(), embeddedLine - 1 + startLine); RetVal.AddService(service); } if (!XMLDoc.IsStartElement()) { if (XMLDoc.LocalName != "serviceList") { XMLDoc.Read(); XMLDoc.MoveToContent(); } } } break; /* case "iconList": bool finishedIconList = false; while (!finishedIconList && XMLDoc.Read()) { switch (XMLDoc.NodeType) { case XmlNodeType.Element: if (XMLDoc.LocalName == "icon") { embeddedLine = XMLDoc.LineNumber; ParseIconXML(RetVal, startLine + embeddedLine-1, XMLDoc.ReadOuterXml()); if (XMLDoc.NodeType == XmlNodeType.EndElement && XMLDoc.LocalName == "iconList") { finishedIconList = true; } } break; case XmlNodeType.EndElement: if (XMLDoc.LocalName == "iconList") { finishedIconList = true; } break; } } break; */ default: if (XMLDoc.LocalName != "") { string customPrefix = XMLDoc.Prefix; string customFieldName = XMLDoc.LocalName; string customFieldNamespace = XMLDoc.LookupNamespace(customPrefix); string customFieldVal = XMLDoc.ReadInnerXml(); RetVal.AddCustomFieldInDescription(customFieldName, customFieldVal, customFieldNamespace); } else { XMLDoc.Skip(); } continue; } XMLDoc.Read(); //XMLDoc.MoveToContent(); } } } catch (XMLParsingException ex) { throw ex; } catch (Exception ex) { throw new XMLParsingException("Invalid Device XML", startLine + XMLDoc.LineNumber, XMLDoc.LinePosition, ex); } }
/// <summary> /// Parses an xml to a UPnP device (either a root or an embedded device) /// </summary> /// <param name="XML">xml containing the device description</param> /// <param name="RetVal">the UPnP device into which the xml data will be parsed</param> private static void ParseDevice(String XML, ref UPnPDevice RetVal) { string TempString; UPnPService service; DText p = new DText(); TextReader MyString = new StringReader(XML); XmlTextReader XMLDoc = new XmlTextReader(MyString); XMLDoc.Read(); XMLDoc.MoveToContent(); if (XMLDoc.LocalName == "device") { if (XMLDoc.AttributeCount > 0) { for (int ax = 0; ax < XMLDoc.AttributeCount; ++ax) { XMLDoc.MoveToAttribute(ax); if (XMLDoc.LocalName == "MaxVersion") { RetVal.SetVersion(XMLDoc.Value); } } XMLDoc.MoveToContent(); XMLDoc.Read(); } else { XMLDoc.Read(); XMLDoc.MoveToContent(); } while (XMLDoc.LocalName != "device" && !XMLDoc.EOF) { switch (XMLDoc.LocalName) { case "deviceList": ParseDeviceList(XMLDoc.ReadOuterXml(), ref RetVal); break; case "URLBase": // Here, tport is a hack to make Windows Home Server visible. WHS does no set the port in the BaseURL and so, you need to keep it from the SSDP message. int tport = 80; if (RetVal.BaseURL != null) tport = RetVal.BaseURL.Port; RetVal.BaseURL = new Uri(XMLDoc.ReadString()); if (RetVal.BaseURL.Port == 80 && RetVal.BaseURL.Port != tport) RetVal.BaseURL = new Uri(RetVal.BaseURL.Scheme + "://" + RetVal.BaseURL.Host + ":" + tport + RetVal.BaseURL.AbsolutePath); break; case "deviceType": RetVal.DeviceURN = XMLDoc.ReadString(); break; case "friendlyName": RetVal.FriendlyName = XMLDoc.ReadString(); break; case "manufacturer": RetVal.Manufacturer = XMLDoc.ReadString(); break; case "manufacturerURL": RetVal.ManufacturerURL = XMLDoc.ReadString(); break; case "modelDescription": RetVal.ModelDescription = XMLDoc.ReadString(); break; case "modelName": RetVal.ModelName = XMLDoc.ReadString(); break; case "modelNumber": RetVal.ModelNumber = XMLDoc.ReadString(); break; case "modelURL": try { string u = XMLDoc.ReadString(); if (Uri.TryCreate(u, UriKind.Absolute, out RetVal.ModelURL) == false) { Uri.TryCreate("http://" + u, UriKind.Absolute, out RetVal.ModelURL); } } catch { } break; case "serialNumber": RetVal.SerialNumber = XMLDoc.ReadString(); break; case "UDN": TempString = XMLDoc.ReadString(); RetVal.UniqueDeviceName = TempString.Substring(5); break; case "UPC": RetVal.ProductCode = XMLDoc.ReadString(); break; case "presentationURL": RetVal.HasPresentation = true; RetVal.PresentationURL = XMLDoc.ReadString(); break; case "serviceList": if (XMLDoc.IsEmptyElement) break; XMLDoc.Read(); XMLDoc.MoveToContent(); while (XMLDoc.LocalName != "serviceList") { if (XMLDoc.LocalName == "service") { // TODO: DONE Resilience case 5a - wrap in try/catch block string servicexml = "Failed to read service xml element from device xml"; try { servicexml = XMLDoc.ReadOuterXml(); service = UPnPService.Parse(servicexml); RetVal.AddService(service); } catch (Exception e) { OpenSource.Utilities.EventLogger.Log(null, System.Diagnostics.EventLogEntryType.Error, "Invalid Service element within Device XML"); OpenSource.Utilities.EventLogger.Log(e, "XML content: \r\n" + servicexml); OpenSource.Utilities.EventLogger.Log(null, System.Diagnostics.EventLogEntryType.Warning, "Dropping failed Service and commencing parsing remainder of device"); } } if (!XMLDoc.IsStartElement()) { if (XMLDoc.LocalName != "serviceList") { XMLDoc.Read(); XMLDoc.MoveToContent(); } } } break; case "iconList": bool finishedIconList = false; while (!finishedIconList && XMLDoc.Read()) { switch (XMLDoc.NodeType) { case XmlNodeType.Element: if (XMLDoc.LocalName == "icon") { ParseIconXML(RetVal, XMLDoc.ReadOuterXml()); if (XMLDoc.NodeType == XmlNodeType.EndElement && XMLDoc.LocalName == "iconList") { finishedIconList = true; } } break; case XmlNodeType.EndElement: if (XMLDoc.LocalName == "iconList") { finishedIconList = true; } break; } } break; default: if (XMLDoc.LocalName != "") { string customPrefix = XMLDoc.Prefix; string customFieldName = XMLDoc.LocalName; string customFieldNamespace = XMLDoc.LookupNamespace(customPrefix); string customFieldVal = XMLDoc.ReadInnerXml(); RetVal.AddCustomFieldInDescription(customFieldName, customFieldVal, customFieldNamespace); } else { XMLDoc.Skip(); } continue; } XMLDoc.Read(); //XMLDoc.MoveToContent(); } } }