diff options
Diffstat (limited to 'lib/libUPnP/Platinum/Source/Core/PltDeviceData.cpp')
-rw-r--r-- | lib/libUPnP/Platinum/Source/Core/PltDeviceData.cpp | 830 |
1 files changed, 830 insertions, 0 deletions
diff --git a/lib/libUPnP/Platinum/Source/Core/PltDeviceData.cpp b/lib/libUPnP/Platinum/Source/Core/PltDeviceData.cpp new file mode 100644 index 0000000..a092b77 --- /dev/null +++ b/lib/libUPnP/Platinum/Source/Core/PltDeviceData.cpp @@ -0,0 +1,830 @@ +/***************************************************************** +| +| Platinum - Device Data +| +| Copyright (c) 2004-2010, Plutinosoft, LLC. +| All rights reserved. +| http://www.plutinosoft.com +| +| This program is free software; you can redistribute it and/or +| modify it under the terms of the GNU General Public License +| as published by the Free Software Foundation; either version 2 +| of the License, or (at your option) any later version. +| +| OEMs, ISVs, VARs and other distributors that combine and +| distribute commercially licensed software with Platinum software +| and do not wish to distribute the source code for the commercially +| licensed software under version 2, or (at your option) any later +| version, of the GNU General Public License (the "GPL") must enter +| into a commercial license agreement with Plutinosoft, LLC. +| licensing@plutinosoft.com +| +| This program is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| You should have received a copy of the GNU General Public License +| along with this program; see the file LICENSE.txt. If not, write to +| the Free Software Foundation, Inc., +| 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +| http://www.gnu.org/licenses/gpl-2.0.html +| +****************************************************************/ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "PltDeviceData.h" +#include "PltService.h" +#include "PltUPnP.h" +#include "PltUtilities.h" + +NPT_SET_LOCAL_LOGGER("platinum.core.devicedata") + +/*---------------------------------------------------------------------- +| PLT_DeviceData::PLT_DeviceData ++---------------------------------------------------------------------*/ +PLT_DeviceData::PLT_DeviceData(NPT_HttpUrl description_url, + const char* uuid, + NPT_TimeInterval lease_time, + const char* device_type, + const char* friendly_name) : + m_Manufacturer("Plutinosoft LLC"), + m_ManufacturerURL("http://www.plutinosoft.com"), + m_UUID(uuid), + m_URLDescription(description_url), + m_DeviceType(device_type), + m_FriendlyName(friendly_name), + m_BootId(0), + m_NextBootId(0) +{ + if (uuid == NULL || strlen(uuid) == 0) { + PLT_UPnPMessageHelper::GenerateGUID(m_UUID); + } + + SetLeaseTime(lease_time); + SetURLBase(m_URLDescription); + UpdateConfigId(); +} + +/*---------------------------------------------------------------------- +| PLT_DeviceData::~PLT_DeviceData ++---------------------------------------------------------------------*/ +PLT_DeviceData::~PLT_DeviceData() +{ + Cleanup(); +} + +/*---------------------------------------------------------------------- +| PLT_DeviceData::Cleanup ++---------------------------------------------------------------------*/ +void +PLT_DeviceData::Cleanup() +{ + m_Services.Apply(NPT_ObjectDeleter<PLT_Service>()); + m_Services.Clear(); + m_EmbeddedDevices.Clear(); + m_Icons.Clear(); +} + +/*---------------------------------------------------------------------- +| PLT_DeviceData::SetDescriptionUrl ++---------------------------------------------------------------------*/ +NPT_Result +PLT_DeviceData::SetDescriptionUrl(NPT_HttpUrl& url) +{ + NPT_CHECK_FATAL(SetURLBase(url)); + m_URLDescription = url; + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| PLT_DeviceData::GetDescriptionUrl ++---------------------------------------------------------------------*/ +NPT_String +PLT_DeviceData::GetDescriptionUrl(const char* ip_address) +{ + NPT_HttpUrl url = m_URLDescription; + + // replace host with ip address specified + if (ip_address) url.SetHost(ip_address); + return url.ToString(); +} + +/*---------------------------------------------------------------------- +| PLT_DeviceData::SetURLBase ++---------------------------------------------------------------------*/ +NPT_Result +PLT_DeviceData::SetURLBase(NPT_HttpUrl& url) +{ + // only http scheme supported + m_URLBase.SetScheme(url.GetScheme()); + + // update port if any + if (url.GetPort() != NPT_URL_INVALID_PORT) m_URLBase.SetPort(url.GetPort()); + + // update host if any + if (!url.GetHost().IsEmpty()) m_URLBase.SetHost(url.GetHost()); + + // update path + NPT_String path = url.GetPath(); + + // remove trailing file according to RFC 2396 + if (!path.EndsWith("/")) { + int index = path.ReverseFind('/'); + if (index < 0) return NPT_FAILURE; + path.SetLength(index+1); + } + m_URLBase.SetPath(path, true); + + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| PLT_DeviceData::GetURLBase ++---------------------------------------------------------------------*/ +NPT_HttpUrl +PLT_DeviceData::GetURLBase() +{ + return m_URLBase; +} + +/*---------------------------------------------------------------------- +| PLT_DeviceData::NormalizeURL ++---------------------------------------------------------------------*/ +NPT_HttpUrl +PLT_DeviceData::NormalizeURL(const NPT_String& url) +{ + if (url.StartsWith("http://")) return NPT_HttpUrl(url); + + NPT_HttpUrl norm_url = m_URLBase; + if (url.StartsWith("/")) { + norm_url.ParsePathPlus(url); + } else { + norm_url.ParsePathPlus(norm_url.GetPath() + url); + } + + return norm_url; +} + +/*---------------------------------------------------------------------- +| PLT_DeviceData::GetIconUrl ++---------------------------------------------------------------------*/ +NPT_String +PLT_DeviceData::GetIconUrl(const char* mimetype, + NPT_Int32 maxsize, + NPT_Int32 maxdepth) +{ + PLT_DeviceIcon icon; + + for (NPT_Cardinal i=0; i<m_Icons.GetItemCount(); i++) { + if ((mimetype && m_Icons[i].m_MimeType != mimetype) || + (maxsize && m_Icons[i].m_Width > maxsize) || + (maxsize && m_Icons[i].m_Height > maxsize) || + (maxdepth && m_Icons[i].m_Depth > maxdepth)) + continue; + + // pick the biggest and better resolution we can + if (icon.m_Width >= m_Icons[i].m_Width || + icon.m_Height >= m_Icons[i].m_Height || + icon.m_Depth >= m_Icons[i].m_Depth || + m_Icons[i].m_UrlPath.IsEmpty()) + continue; + + icon = m_Icons[i]; + } + + if (icon.m_UrlPath == "") return ""; + + return NormalizeURL(icon.m_UrlPath).ToString(); +} + +/*---------------------------------------------------------------------- +| PLT_DeviceData::UpdateConfigId ++---------------------------------------------------------------------*/ +void +PLT_DeviceData::UpdateConfigId() +{ + NPT_UInt32 nextConfigId = NPT_System::GetRandomInteger() & 0xFFFFFF; + if (m_ConfigId == nextConfigId) { + // prevent value to underflow + nextConfigId>0?--nextConfigId:++nextConfigId; + } + + m_ConfigId = nextConfigId; +} + +/*---------------------------------------------------------------------- +| PLT_DeviceData::SetBootId ++---------------------------------------------------------------------*/ +void +PLT_DeviceData::SetBootId(NPT_UInt32 bootId) +{ + m_BootId = bootId; +} + +/*---------------------------------------------------------------------- + | PLT_DeviceData::SetNextBootId + +---------------------------------------------------------------------*/ +void +PLT_DeviceData::SetNextBootId(NPT_UInt32 nextBootId) +{ + m_NextBootId = nextBootId; +} + +/*---------------------------------------------------------------------- +| PLT_DeviceData::GenerateNextBootId ++---------------------------------------------------------------------*/ +NPT_UInt32 +PLT_DeviceData::GenerateNextBootId() +{ + NPT_TimeStamp now; + NPT_System::GetCurrentTimeStamp(now); + NPT_UInt32 value = (NPT_UInt32)now.ToSeconds(); + if (value == m_BootId) ++value; + return value; +} + +/*---------------------------------------------------------------------- +| PLT_DeviceData::SetLeaseTime ++---------------------------------------------------------------------*/ +NPT_Result +PLT_DeviceData::SetLeaseTime(NPT_TimeInterval lease_time, NPT_TimeStamp lease_time_last_update /* = 0 */) +{ + // Enforce 10 seconds min lease time + m_LeaseTime = (lease_time.ToSeconds()>=10)?lease_time:*PLT_Constants::GetInstance().GetDefaultDeviceLease(); + + // get current time as last update time if none passed + if ((double)lease_time_last_update == 0.) { + NPT_System::GetCurrentTimeStamp(lease_time_last_update); + } + m_LeaseTimeLastUpdate = lease_time_last_update; + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| PLT_DeviceData::GetLeaseTimeLastUpdate ++---------------------------------------------------------------------*/ +NPT_TimeStamp +PLT_DeviceData::GetLeaseTimeLastUpdate() +{ + return m_LeaseTimeLastUpdate; +} + +/*---------------------------------------------------------------------- +| PLT_DeviceData::operator const char*() ++---------------------------------------------------------------------*/ +PLT_DeviceData::operator const char*() +{ + NPT_StringOutputStreamReference stream(new NPT_StringOutputStream); + stream->WriteString("Device GUID: "); + stream->WriteString((const char*)m_UUID); + + stream->WriteString("Device Type: "); + stream->WriteString((const char*)m_DeviceType); + + stream->WriteString("Device Base Url: "); + stream->WriteString((const char*)GetURLBase().ToString()); + + stream->WriteString("Device Friendly Name: "); + stream->WriteString((const char*)m_FriendlyName); + + m_Representation = stream->GetString(); + return m_Representation; +} + +/*---------------------------------------------------------------------- +| PLT_DeviceData::AddEmbeddedDevice ++---------------------------------------------------------------------*/ +NPT_Result +PLT_DeviceData::AddEmbeddedDevice(PLT_DeviceDataReference& device) +{ + UpdateConfigId(); + + device->m_ParentUUID = m_UUID; + return m_EmbeddedDevices.Add(device); +} + +/*---------------------------------------------------------------------- +| PLT_DeviceData::RemoveEmbeddedDevice ++---------------------------------------------------------------------*/ +NPT_Result +PLT_DeviceData::RemoveEmbeddedDevice(PLT_DeviceDataReference& device) +{ + for (NPT_Cardinal i=0; + i<m_EmbeddedDevices.GetItemCount(); + i++) { + if (m_EmbeddedDevices[i] == device) { + UpdateConfigId(); + return m_EmbeddedDevices.Erase(i); + } + } + + return NPT_ERROR_NO_SUCH_ITEM; +} + +/*---------------------------------------------------------------------- +| PLT_DeviceData::AddService ++---------------------------------------------------------------------*/ +NPT_Result +PLT_DeviceData::AddService(PLT_Service* service) +{ + if (service->GetServiceType() == "" || + service->GetServiceID() == "" || + service->GetSCPDURL() == "" || + service->GetControlURL() == "" || + service->GetEventSubURL() == "") { + return NPT_ERROR_INVALID_PARAMETERS; + } + UpdateConfigId(); + return m_Services.Add(service); +} + +/*---------------------------------------------------------------------- +| PLT_DeviceData::RemoveService ++---------------------------------------------------------------------*/ +NPT_Result +PLT_DeviceData::RemoveService(PLT_Service* service) +{ + for (NPT_Cardinal i=0; + i<m_Services.GetItemCount(); + i++) { + if (m_Services[i] == service) { + UpdateConfigId(); + return m_Services.Erase(i); + } + } + + return NPT_ERROR_NO_SUCH_ITEM; +} + +/*---------------------------------------------------------------------- +| PLT_GetDescriptionIterator class ++---------------------------------------------------------------------*/ +template <class T> +class PLT_GetDescriptionIterator +{ +public: + PLT_GetDescriptionIterator<T>(NPT_XmlElementNode* parent) : + m_Parent(parent) {} + + NPT_Result operator()(T& data) const { + return data->GetDescription(m_Parent); + } + +private: + NPT_XmlElementNode* m_Parent; +}; + +/*---------------------------------------------------------------------- +| PLT_DeviceData::GetDescription ++---------------------------------------------------------------------*/ +NPT_Result +PLT_DeviceData::GetDescription(NPT_XmlElementNode* root, NPT_XmlElementNode** device_out) +{ + NPT_XmlElementNode* device = new NPT_XmlElementNode("device"); + if (device_out) *device_out = device; + + NPT_CHECK_SEVERE(root->AddChild(device)); + + // device properties + NPT_CHECK_SEVERE(PLT_XmlHelper::AddChildText(device, "deviceType", m_DeviceType)); + NPT_CHECK_SEVERE(PLT_XmlHelper::AddChildText(device, "friendlyName", m_FriendlyName)); + NPT_CHECK_SEVERE(PLT_XmlHelper::AddChildText(device, "manufacturer", m_Manufacturer)); + NPT_CHECK_SEVERE(PLT_XmlHelper::AddChildText(device, "manufacturerURL", m_ManufacturerURL)); + NPT_CHECK_SEVERE(PLT_XmlHelper::AddChildText(device, "modelDescription", m_ModelDescription)); + NPT_CHECK_SEVERE(PLT_XmlHelper::AddChildText(device, "modelName", m_ModelName)); + if (!m_ModelNumber.IsEmpty()) NPT_CHECK_SEVERE(PLT_XmlHelper::AddChildText(device, "modelNumber", m_ModelNumber)); + if (!m_SerialNumber.IsEmpty()) NPT_CHECK_SEVERE(PLT_XmlHelper::AddChildText(device, "serialNumber", m_SerialNumber)); + NPT_CHECK_SEVERE(PLT_XmlHelper::AddChildText(device, "modelURL", m_ModelURL)); // moved after modelNumber to go around a bug in UCTT + NPT_CHECK_SEVERE(PLT_XmlHelper::AddChildText(device, "UDN", "uuid:" + m_UUID)); + + if (!m_PresentationURL.IsEmpty()) { + NPT_CHECK_SEVERE(PLT_XmlHelper::AddChildText(device, "presentationURL", m_PresentationURL)); + } + + // Extra info not in UPnP specs + NPT_CHECK(OnAddExtraInfo(device)); + + // DLNA support + if (!m_DlnaDoc.IsEmpty()) { + NPT_XmlElementNode* dlnadoc = new NPT_XmlElementNode("dlna", "X_DLNADOC"); + NPT_CHECK_SEVERE(dlnadoc->SetNamespaceUri("dlna", "urn:schemas-dlna-org:device-1-0")); + dlnadoc->AddText(m_DlnaDoc); + device->AddChild(dlnadoc); + } + if (!m_DlnaCap.IsEmpty()) { + NPT_XmlElementNode* dlnacap = new NPT_XmlElementNode("dlna", "X_DLNACAP"); + NPT_CHECK_SEVERE(dlnacap->SetNamespaceUri("dlna", "urn:schemas-dlna-org:device-1-0")); + dlnacap->AddText(m_DlnaCap); + device->AddChild(dlnacap); + } + + // icons + if (m_Icons.GetItemCount()) { + NPT_XmlElementNode* icons = new NPT_XmlElementNode("iconList"); + NPT_CHECK_SEVERE(device->AddChild(icons)); + for (NPT_Cardinal i=0; i<m_Icons.GetItemCount(); i++) { + NPT_XmlElementNode* icon = new NPT_XmlElementNode("icon"); + NPT_CHECK_SEVERE(icons->AddChild(icon)); + NPT_CHECK_SEVERE(PLT_XmlHelper::AddChildText(icon, "mimetype", m_Icons[i].m_MimeType)); + NPT_CHECK_SEVERE(PLT_XmlHelper::AddChildText(icon, "width", NPT_String::FromInteger(m_Icons[i].m_Width))); + NPT_CHECK_SEVERE(PLT_XmlHelper::AddChildText(icon, "height", NPT_String::FromInteger(m_Icons[i].m_Height))); + NPT_CHECK_SEVERE(PLT_XmlHelper::AddChildText(icon, "depth", NPT_String::FromInteger(m_Icons[i].m_Depth))); + NPT_CHECK_SEVERE(PLT_XmlHelper::AddChildText(icon, "url", m_Icons[i].m_UrlPath)); + } + } + + // services + NPT_XmlElementNode* services = new NPT_XmlElementNode("serviceList"); + NPT_CHECK_SEVERE(device->AddChild(services)); + NPT_CHECK_SEVERE(m_Services.ApplyUntil(PLT_GetDescriptionIterator<PLT_Service*>(services), + NPT_UntilResultNotEquals(NPT_SUCCESS))); + + // PS3 support + if (!m_AggregationFlags.IsEmpty()) { + NPT_XmlElementNode* aggr = new NPT_XmlElementNode("av", "aggregationFlags"); + NPT_CHECK_SEVERE(aggr->SetNamespaceUri("av", "urn:schemas-sonycom:av")); + aggr->AddText(m_AggregationFlags); + device->AddChild(aggr); + } + + // embedded devices + if (m_EmbeddedDevices.GetItemCount()) { + NPT_XmlElementNode* deviceList = new NPT_XmlElementNode("deviceList"); + NPT_CHECK_SEVERE(device->AddChild(deviceList)); + + NPT_CHECK_SEVERE(m_EmbeddedDevices.ApplyUntil( + PLT_GetDescriptionIterator<PLT_DeviceDataReference>(deviceList), + NPT_UntilResultNotEquals(NPT_SUCCESS))); + } + + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| PLT_DeviceData::GetDescription ++---------------------------------------------------------------------*/ +NPT_Result +PLT_DeviceData::GetDescription(NPT_String& desc) +{ + NPT_Result res; + NPT_XmlElementNode* spec = NULL; + NPT_XmlElementNode* root = new NPT_XmlElementNode("root"); + + NPT_CHECK_LABEL_SEVERE(res = root->SetNamespaceUri("", "urn:schemas-upnp-org:device-1-0"), cleanup); + NPT_CHECK_LABEL_SEVERE(res = root->SetNamespaceUri("dlna", "urn:schemas-dlna-org:device-1-0"), cleanup); + NPT_CHECK_LABEL_SEVERE(res = root->SetAttribute("", "configId", NPT_String::FromInteger(m_ConfigId)), cleanup); + + // add spec version + spec = new NPT_XmlElementNode("specVersion"); + NPT_CHECK_LABEL_SEVERE(res = root->AddChild(spec), cleanup); + NPT_CHECK_LABEL_SEVERE(res = PLT_XmlHelper::AddChildText(spec, "major", "1"), cleanup); + NPT_CHECK_LABEL_SEVERE(res = PLT_XmlHelper::AddChildText(spec, "minor", "1"), cleanup); + + // get device xml + NPT_CHECK_LABEL_SEVERE(res = GetDescription(root), cleanup); + + // serialize node + NPT_CHECK_LABEL_SEVERE(res = PLT_XmlHelper::Serialize(*root, desc, true, 2), cleanup); + +cleanup: + delete root; + return res; +} + +/*---------------------------------------------------------------------- +| PLT_DeviceData::SetDescription ++---------------------------------------------------------------------*/ +NPT_Result +PLT_DeviceData::SetDescription(PLT_DeviceDataReference& root_device, + NPT_TimeInterval leasetime, + NPT_HttpUrl description_url, + const char* description, + const NPT_HttpRequestContext& context) +{ + NPT_XmlParser parser; + NPT_XmlNode* tree = NULL; + NPT_Result res; + NPT_XmlElementNode* root = NULL; + NPT_String URLBase; + NPT_String configId; + + // create new device if none passed + if (root_device.IsNull()) { + root_device = new PLT_DeviceData(description_url, "", leasetime); + } + + res = parser.Parse(description, tree); + NPT_CHECK_LABEL_SEVERE(res, cleanup); + + root = tree->AsElementNode(); + if (!root || + root->GetTag() != "root" || + !root->GetNamespace() || + *root->GetNamespace() != "urn:schemas-upnp-org:device-1-0") { + NPT_LOG_INFO_1("root namespace is invalid: %s", + (root&&root->GetNamespace())?root->GetNamespace()->GetChars():"null"); + NPT_CHECK_LABEL_SEVERE(NPT_FAILURE, cleanup); + } + + // look for optional URLBase element + if (NPT_SUCCEEDED(PLT_XmlHelper::GetChildText(root, "URLBase", URLBase))) { + NPT_HttpUrl url(URLBase); + // Some devices like Connect360 try to be funny - not so + if (url.GetHost().ToLowercase() == "localhost" || + url.GetHost().ToLowercase() == "127.0.0.1") { + url.SetHost(context.GetRemoteAddress().GetIpAddress().ToString()); + } + root_device->SetURLBase(url); + } else { + // No URLBase, derive from description url + root_device->SetURLBase(description_url); + } + + // at least one root device child element is required + NPT_XmlElementNode* device; + if (!(device = PLT_XmlHelper::GetChild(root, "device"))) { + NPT_CHECK_LABEL_SEVERE(NPT_FAILURE, cleanup); + } + + res = SetDescriptionDevice(root_device, device, context); + + // reset configId if and set it back from root attribute + root_device->m_ConfigId = 0; + if (NPT_SUCCEEDED(PLT_XmlHelper::GetAttribute(root, "configId", configId))) { + NPT_UInt32 value; + if (NPT_SUCCEEDED(configId.ToInteger32(value))) { + root_device->m_ConfigId = value; + } + } + +cleanup: + // delete the tree + delete tree; + return res; +} + +/*---------------------------------------------------------------------- +| PLT_DeviceData::SetDescriptionDevice ++---------------------------------------------------------------------*/ +NPT_Result +PLT_DeviceData::SetDescriptionDevice(PLT_DeviceDataReference& device, + NPT_XmlElementNode* device_node, + const NPT_HttpRequestContext& context) +{ + NPT_Result res; + + device->m_LocalIfaceIp = context.GetLocalAddress().GetIpAddress(); + + NPT_CHECK_SEVERE(PLT_XmlHelper::GetChildText(device_node, "deviceType", device->m_DeviceType)); + NPT_CHECK_SEVERE(PLT_XmlHelper::GetChildText(device_node, "UDN", device->m_UUID)); + + // remove uuid: prefix + if (device->m_UUID.StartsWith("uuid:")) { + device->m_UUID = ((const char*)device->m_UUID)+5; + } + + // optional attributes + PLT_XmlHelper::GetChildText(device_node, "friendlyName", device->m_FriendlyName); + PLT_XmlHelper::GetChildText(device_node, "manufacturer", device->m_Manufacturer); + PLT_XmlHelper::GetChildText(device_node, "manufacturerURL", device->m_ManufacturerURL); + PLT_XmlHelper::GetChildText(device_node, "modelDescription", device->m_ModelDescription); + PLT_XmlHelper::GetChildText(device_node, "modelName", device->m_ModelName); + PLT_XmlHelper::GetChildText(device_node, "modelURL", device->m_ModelURL); + PLT_XmlHelper::GetChildText(device_node, "modelNumber", device->m_ModelNumber); + PLT_XmlHelper::GetChildText(device_node, "serialNumber", device->m_SerialNumber); + PLT_XmlHelper::GetChildText(device_node, "presentationURL", device->m_PresentationURL); + + // enumerate icons + NPT_XmlElementNode* iconList = PLT_XmlHelper::GetChild(device_node, "iconList"); + if (iconList) { + NPT_Array<NPT_XmlElementNode*> icons; + PLT_XmlHelper::GetChildren(iconList, icons, "icon"); + + for (NPT_Cardinal k=0 ; k<icons.GetItemCount(); k++) { + PLT_DeviceIcon icon; + NPT_String integer, height, depth; + + PLT_XmlHelper::GetChildText(icons[k], "mimetype", icon.m_MimeType); + PLT_XmlHelper::GetChildText(icons[k], "url", icon.m_UrlPath); + + if(NPT_SUCCEEDED(PLT_XmlHelper::GetChildText(icons[k], "width", integer))) + NPT_ParseInteger32(integer, icon.m_Width); + if(NPT_SUCCEEDED(PLT_XmlHelper::GetChildText(icons[k], "height", integer))) + NPT_ParseInteger32(integer, icon.m_Height); + if(NPT_SUCCEEDED(PLT_XmlHelper::GetChildText(icons[k], "depth", integer))) + NPT_ParseInteger32(integer, icon.m_Depth); + + device->m_Icons.Add(icon); + } + } + + // enumerate device services + NPT_XmlElementNode* serviceList = PLT_XmlHelper::GetChild(device_node, "serviceList"); + if (serviceList) { + NPT_Array<NPT_XmlElementNode*> services; + PLT_XmlHelper::GetChildren(serviceList, services, "service"); + for( int k = 0 ; k < (int)services.GetItemCount(); k++) { + NPT_String type, id, url; + PLT_XmlHelper::GetChildText(services[k], "serviceType", type); + PLT_XmlHelper::GetChildText(services[k], "serviceId", id); + PLT_Service* service = new PLT_Service(device.AsPointer(), type, id, NULL); + + PLT_XmlHelper::GetChildText(services[k], "SCPDURL", url); + service->SetSCPDURL(url); + + PLT_XmlHelper::GetChildText(services[k], "controlURL", url); + service->SetControlURL(url); + + PLT_XmlHelper::GetChildText(services[k], "eventSubURL", url); + service->SetEventSubURL(url); + + if (NPT_FAILED(res = device->AddService(service))) { + delete service; + return res; + } + } + } + + // enumerate embedded devices + NPT_XmlElementNode* deviceList = PLT_XmlHelper::GetChild(device_node, "deviceList"); + if (deviceList) { + NPT_Array<NPT_XmlElementNode*> devices; + PLT_XmlHelper::GetChildren(deviceList, devices, "device"); + for (int k = 0; k<(int)devices.GetItemCount(); k++) { + // create an embedded device with same url base and leasetime as parent + PLT_DeviceDataReference embedded_device(new PLT_DeviceData(device->m_URLDescription, "", device->m_LeaseTime)); + NPT_CHECK_SEVERE(PLT_DeviceData::SetDescriptionDevice(embedded_device, devices[k], context)); + device->AddEmbeddedDevice(embedded_device); + } + } + + // TODO: Parse extra DLNA stuff + + return NPT_SUCCESS; +} + + +/*---------------------------------------------------------------------- +| PLT_DeviceData::FindEmbeddedDevice ++---------------------------------------------------------------------*/ +NPT_Result +PLT_DeviceData::FindEmbeddedDevice(const char* uuid, + PLT_DeviceDataReference& device) +{ + NPT_Result res = NPT_ContainerFind(m_EmbeddedDevices, + PLT_DeviceDataFinder(uuid), + device); + if (NPT_SUCCEEDED(res)) return res; + + for (int i=0; i<(int)m_EmbeddedDevices.GetItemCount(); i++) { + res = m_EmbeddedDevices[i]->FindEmbeddedDevice( + uuid, + device); + if (NPT_SUCCEEDED(res)) return res; + } + + return NPT_FAILURE; +} + +/*---------------------------------------------------------------------- +| PLT_DeviceData::FindEmbeddedDeviceByType ++---------------------------------------------------------------------*/ +NPT_Result +PLT_DeviceData::FindEmbeddedDeviceByType(const char* type, + PLT_DeviceDataReference& device) +{ + NPT_Result res = NPT_ContainerFind(m_EmbeddedDevices, + PLT_DeviceDataFinderByType(type), + device); + if (NPT_SUCCEEDED(res)) return res; + + for (int i=0; i<(int)m_EmbeddedDevices.GetItemCount(); i++) { + res = m_EmbeddedDevices[i]->FindEmbeddedDeviceByType( + type, + device); + if (NPT_SUCCEEDED(res)) return res; + } + + return NPT_FAILURE; +} + +/*---------------------------------------------------------------------- +| PLT_DeviceData::FindServiceById ++---------------------------------------------------------------------*/ +NPT_Result +PLT_DeviceData::FindServiceById(const char* id, PLT_Service*& service) +{ + // do not try to find it within embedded devices, since different + // embedded devices could have an identical service + return NPT_ContainerFind(m_Services, + PLT_ServiceIDFinder(id), + service); +} + +/*---------------------------------------------------------------------- +| PLT_DeviceData::FindServiceByType ++---------------------------------------------------------------------*/ +NPT_Result +PLT_DeviceData::FindServiceByType(const char* type, PLT_Service*& service) +{ + // do not try to find it within embedded devices, since different + // embedded devices could have an identical service + return NPT_ContainerFind(m_Services, + PLT_ServiceTypeFinder(type), + service); +} + +/*---------------------------------------------------------------------- +| PLT_DeviceData::FindServiceByName ++---------------------------------------------------------------------*/ +NPT_Result +PLT_DeviceData::FindServiceByName(const char* name, PLT_Service*& service) +{ + // do not try to find it within embedded devices, since different + // embedded devices could have an identical service + return NPT_ContainerFind(m_Services, + PLT_ServiceNameFinder(name), + service); +} + +/*---------------------------------------------------------------------- +| PLT_DeviceData::FindServiceBySCPDURL ++---------------------------------------------------------------------*/ +NPT_Result +PLT_DeviceData::FindServiceBySCPDURL(const char* url, + PLT_Service*& service, + bool recursive /* = false */) +{ + NPT_Result res = NPT_ContainerFind( + m_Services, + PLT_ServiceSCPDURLFinder(url), + service); + if (NPT_SUCCEEDED(res)) return res; + + if (recursive) { + for (int i=0; i<(int)m_EmbeddedDevices.GetItemCount(); i++) { + res = m_EmbeddedDevices[i]->FindServiceBySCPDURL( + url, + service, + recursive); + if (NPT_SUCCEEDED(res)) return res; + } + } + + return NPT_FAILURE; +} + +/*---------------------------------------------------------------------- +| PLT_DeviceData::FindServiceByControlURL ++---------------------------------------------------------------------*/ +NPT_Result +PLT_DeviceData::FindServiceByControlURL(const char* url, + PLT_Service*& service, + bool recursive /* = false */) +{ + NPT_Result res = NPT_ContainerFind(m_Services, + PLT_ServiceControlURLFinder(url), + service); + if (NPT_SUCCEEDED(res)) return res; + + if (recursive) { + for (int i=0; i<(int)m_EmbeddedDevices.GetItemCount(); i++) { + res = m_EmbeddedDevices[i]->FindServiceByControlURL( + url, + service, + recursive); + if (NPT_SUCCEEDED(res)) return res; + } + } + + return NPT_FAILURE; +} + +/*---------------------------------------------------------------------- +| PLT_DeviceData::FindServiceByEventSubURL ++---------------------------------------------------------------------*/ +NPT_Result +PLT_DeviceData::FindServiceByEventSubURL(const char* url, + PLT_Service*& service, + bool recursive /* = false */) +{ + NPT_Result res = NPT_ContainerFind(m_Services, + PLT_ServiceEventSubURLFinder(url), + service); + if (NPT_SUCCEEDED(res)) return res; + + if (recursive) { + for (int i=0; i<(int)m_EmbeddedDevices.GetItemCount(); i++) { + res = m_EmbeddedDevices[i]->FindServiceByEventSubURL( + url, + service, + recursive); + if (NPT_SUCCEEDED(res)) return res; + } + } + + return NPT_FAILURE; +} |