/*---------------------------------------------------------------------- | 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); // 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", "0"), 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_StateVariable::GetSCPDXML +---------------------------------------------------------------------*/ NPT_Result PLT_StateVariable::GetSCPDXML(NPT_XmlElementNode* node) { NPT_XmlElementNode* variable = new NPT_XmlElementNode("stateVariable"); NPT_CHECK_SEVERE(node->AddChild(variable)); NPT_CHECK_SEVERE(variable->SetAttribute("sendEvents", m_IsSendingEvents?"yes":"no")); NPT_CHECK_SEVERE(PLT_XmlHelper::AddChildText(variable, "name", m_Name)); NPT_CHECK_SEVERE(PLT_XmlHelper::AddChildText(variable, "dataType", m_DataType)); if (m_DefaultValue.GetLength()) { NPT_CHECK_SEVERE(PLT_XmlHelper::AddChildText(variable, "defaultValue", m_DefaultValue)); } if (m_AllowedValues.GetItemCount()) { NPT_XmlElementNode* allowedValueList = new NPT_XmlElementNode("allowedValueList"); NPT_CHECK_SEVERE(variable->AddChild(allowedValueList)); for( int l = 0 ; l < (int)m_AllowedValues.GetItemCount(); l++) { NPT_CHECK_SEVERE(PLT_XmlHelper::AddChildText(allowedValueList, "allowedValue", (*m_AllowedValues[l]))); } } else if (m_AllowedValueRange) { NPT_XmlElementNode* range = new NPT_XmlElementNode("allowedValueRange"); NPT_CHECK_SEVERE(variable->AddChild(range)); NPT_CHECK_SEVERE(PLT_XmlHelper::AddChildText(range, "minimum", NPT_String::FromInteger(m_AllowedValueRange->min_value))); NPT_CHECK_SEVERE(PLT_XmlHelper::AddChildText(range, "maximum", NPT_String::FromInteger(m_AllowedValueRange->max_value))); if (m_AllowedValueRange->step != -1) { NPT_CHECK_SEVERE(PLT_XmlHelper::AddChildText(range, "step", NPT_String::FromInteger(m_AllowedValueRange->step))); } } return NPT_SUCCESS; }
/*---------------------------------------------------------------------- | TestMakeStandalone +---------------------------------------------------------------------*/ static void TestMakeStandalone() { const char* xml = "<parent xmlns:foo='foo-ns' xmlns:bar='bar-ns' xmlns='default-ns'><inter xmlns:bli='bli-ns' xmlns:bou='bou-ns'><child><foo:a>a-text</foo:a><bar:b xml:fifi='0'>b-text</bar:b><c>c-text</c><d bou:att='b-att'/></child></inter></parent>"; const char* expected = "<child xmlns=\"default-ns\" xmlns:foo=\"foo-ns\" xmlns:bar=\"bar-ns\" xmlns:bou=\"bou-ns\"><foo:a>a-text</foo:a><bar:b xml:fifi=\"0\">b-text</bar:b><c>c-text</c><d bou:att=\"b-att\"/></child>"; NPT_XmlParser parser; NPT_XmlNode* root = NULL; NPT_Result result = parser.Parse(xml, root); CHECK(NPT_SUCCEEDED(result)); CHECK(root != NULL); CHECK(root->AsElementNode() != NULL); NPT_XmlElementNode* inter = root->AsElementNode()->GetChild("inter", NPT_XML_ANY_NAMESPACE); CHECK(inter != NULL); NPT_XmlElementNode* child = inter->GetChild("child", NPT_XML_ANY_NAMESPACE); CHECK(child != NULL); child->MakeStandalone(); NPT_XmlWriter writer; NPT_MemoryStream buffer; writer.Serialize(*child, buffer); CHECK(buffer.GetBuffer() == NPT_DataBuffer(expected, NPT_StringLength(expected))); delete root; }
/*---------------------------------------------------------------------- | 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; // 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); cleanup: // delete the tree delete tree; return res; }
/*---------------------------------------------------------------------- | PLT_StateVariable::Serialize +---------------------------------------------------------------------*/ NPT_Result PLT_StateVariable::Serialize(NPT_XmlElementNode& node) { NPT_List<NPT_Map<NPT_String, NPT_String>::Entry*>::Iterator entry = m_ExtraAttributes.GetEntries().GetFirstItem(); while (entry) { const NPT_String& key = (*entry)->GetKey(); const NPT_String& value = (*entry)->GetValue(); node.SetAttribute(key, value); ++entry; } return node.SetAttribute("val", GetValue()); }
/*---------------------------------------------------------------------- | PLT_ArgumentDesc::GetSCPDXML +---------------------------------------------------------------------*/ NPT_Result PLT_ArgumentDesc::GetSCPDXML(NPT_XmlElementNode* node) { NPT_XmlElementNode* argument = new NPT_XmlElementNode("argument"); NPT_CHECK_SEVERE(node->AddChild(argument)); NPT_CHECK_SEVERE(PLT_XmlHelper::AddChildText(argument, "name", m_Name)); NPT_CHECK_SEVERE(PLT_XmlHelper::AddChildText(argument, "direction", m_Direction)); NPT_CHECK_SEVERE(PLT_XmlHelper::AddChildText(argument, "relatedStateVariable", m_RelatedStateVariable->GetName())); if (m_HasReturnValue) { NPT_CHECK_SEVERE(argument->AddChild(new NPT_XmlElementNode("retval"))); } return NPT_SUCCESS; }
/*---------------------------------------------------------------------- | PLT_MediaServer::ParseTagList +---------------------------------------------------------------------*/ NPT_Result PLT_MediaServer::ParseTagList(const NPT_String& updates, NPT_Map<NPT_String,NPT_String>& tags) { // reset output params first tags.Clear(); NPT_List<NPT_String> split = updates.Split(","); NPT_XmlNode* node = NULL; NPT_XmlElementNode* didl_partial = NULL; NPT_XmlParser parser; // as these are single name value pairs, separated by commas we wrap in a tag // to create a valid tree NPT_String xml("<TagValueList>"); for (NPT_List<NPT_String>::Iterator entry = split.GetFirstItem(); entry; entry++) { NPT_String& element = (*entry); if (element.IsEmpty()) xml.Append("<empty>empty</empty>"); else xml.Append(element); } xml.Append("</TagValueList>"); NPT_LOG_FINE("Parsing TagList..."); NPT_CHECK_LABEL_SEVERE(parser.Parse(xml, node), cleanup); if (!node || !node->AsElementNode()) { NPT_LOG_SEVERE("Invalid node type"); goto cleanup; } didl_partial = node->AsElementNode(); if (didl_partial->GetTag().Compare("TagValueList", true)) { NPT_LOG_SEVERE("Invalid node tag"); goto cleanup; } for (NPT_List<NPT_XmlNode*>::Iterator children = didl_partial->GetChildren().GetFirstItem(); children; children++) { NPT_XmlElementNode* child = (*children)->AsElementNode(); if (!child) continue; tags[child->GetTag()] = *child->GetText(); } return NPT_SUCCESS; cleanup: if (node) delete node; return NPT_FAILURE; }
/*---------------------------------------------------------------------- | PLT_DeviceData::SetDescription +---------------------------------------------------------------------*/ NPT_Result PLT_DeviceData::SetDescription(const char* description, const NPT_IpAddress& local_iface_ip) { NPT_XmlParser parser; NPT_XmlNode* tree = NULL; NPT_Result res; res = parser.Parse(description, tree); if (NPT_FAILED(res)) { delete tree; return res; } NPT_XmlElementNode* root = tree->AsElementNode(); if (!root || root->GetTag() != "root" || !root->GetNamespace() || *root->GetNamespace() != "urn:schemas-upnp-org:device-1-0") { delete tree; return NPT_FAILURE; } // look for optional URLBase element NPT_String URLBase; if (NPT_SUCCEEDED(PLT_XmlHelper::GetChildText(root, "URLBase", URLBase))) { NPT_HttpUrl url(URLBase); if (!url.IsValid()) return NPT_FAILURE; SetURLBase(url); } // at least one root device child element is required NPT_XmlElementNode* device; if (!(device = PLT_XmlHelper::GetChild(root, "device"))) { delete tree; return NPT_FAILURE; } res = SetDescriptionDevice(device); // delete the tree delete tree; m_LocalIfaceIp = local_iface_ip; return res; }
/*---------------------------------------------------------------------- | TestWriter +---------------------------------------------------------------------*/ static void TestWriter() { NPT_XmlElementNode* top = new NPT_XmlElementNode("top"); NPT_XmlElementNode* child1 = new NPT_XmlElementNode("child1"); child1->SetAttribute("someAttribute", "someValue"); top->AddChild(child1); NPT_XmlElementNode* child2 = new NPT_XmlElementNode("child2"); child2->SetAttribute("someOtherAttribute", "someOtherValue"); child2->AddText("Some Text"); child1->AddChild(child2); NPT_XmlElementNode* child3 = new NPT_XmlElementNode("child3"); child3->SetAttribute("thirdArrtibute", "3"); child2->AddChild(child3); NPT_XmlWriter writer; NPT_File out(NPT_FILE_STANDARD_OUTPUT); out.Open(NPT_FILE_OPEN_MODE_WRITE); NPT_OutputStreamReference out_stream; out.GetOutputStream(out_stream); writer.Serialize(*top, *out_stream); }
/*---------------------------------------------------------------------- | TestRegression +---------------------------------------------------------------------*/ static void TestRegression() { // test for a bug found when the XML parser would try // to compare a null prefix NPT_XmlElementNode* element = new NPT_XmlElementNode("hello"); element->SetAttribute("ns", "foo", "6"); element->SetAttribute("foo", "5"); element->SetAttribute("ns", "foo", "7"); element->SetAttribute("foo", "8"); element->SetNamespaceUri("ns", "blabla"); CHECK(*element->GetAttribute("foo") == "8"); CHECK(*element->GetAttribute("foo", "blabla") == "7"); delete element; }
/*---------------------------------------------------------------------- | 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)); NPT_CHECK_SEVERE(PLT_XmlHelper::AddChildText(device, "modelURL", m_ModelURL)); if (!m_ModelNumber.IsEmpty()) NPT_CHECK_SEVERE(PLT_XmlHelper::AddChildText(device, "modelNumber", m_ModelNumber)); NPT_CHECK_SEVERE(PLT_XmlHelper::AddChildText(device, "serialNumber", m_SerialNumber)); 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; }
/*---------------------------------------------------------------------- | TestFinders +---------------------------------------------------------------------*/ static void TestFinders() { const char* xml = "<a b='foo' c='bar' ns:b='bla' ns:d='123' xmlns:ns='ns-uri' xmlns:ns1='ns1-uri' xmlns:ns2='ns2-uri' xmlns:ns3='ns3-uri'><b xmlns='ns4-uri' ba='123' ns2:bo='345'></b><b ba='123' ns2:bo='345'></b><ns2:b></ns2:b><ns1:b></ns1:b></a>"; NPT_XmlParser parser; NPT_XmlNode* root; CHECK(NPT_SUCCEEDED(parser.Parse(xml, root))); NPT_XmlElementNode* elem = root->AsElementNode(); const NPT_String* attr = elem->GetAttribute("d"); CHECK(attr == NULL); attr = elem->GetAttribute("b"); CHECK(attr != NULL && *attr == "foo"); attr = elem->GetAttribute("b", "ns-uri"); CHECK(attr != NULL && *attr == "bla"); attr = elem->GetAttribute("c", NPT_XML_ANY_NAMESPACE); CHECK(attr != NULL && *attr == "bar"); attr = elem->GetAttribute("b", NPT_XML_ANY_NAMESPACE); CHECK(attr != NULL && *attr == "foo"); attr = elem->GetAttribute("b", "boubou"); CHECK(attr == NULL); attr = elem->GetAttribute("d", NPT_XML_NO_NAMESPACE); CHECK(attr == NULL); NPT_XmlElementNode* child; child = elem->GetChild("b"); CHECK(child != NULL && *child->GetAttribute("ba") == "123"); child = elem->GetChild("b", "ns4-uri"); CHECK(child != NULL && child->GetAttribute("ba", "ns4-uri") == NULL); CHECK(child != NULL && *child->GetAttribute("bo", NPT_XML_ANY_NAMESPACE) == "345"); CHECK(child != NULL && child->GetAttribute("bo", NPT_XML_NO_NAMESPACE) == NULL); CHECK(child != NULL && child->GetAttribute("bo", "foo") == NULL); CHECK(child != NULL && *child->GetAttribute("bo", "ns2-uri") == "345"); child = elem->GetChild("b", NPT_XML_ANY_NAMESPACE); CHECK(child != NULL && *child->GetNamespace() == "ns4-uri"); child = elem->GetChild("b", "ns2-uri"); CHECK(child != NULL && *child->GetNamespace() == "ns2-uri"); child = elem->GetChild("b", "boubou"); CHECK(child == NULL); delete root; }
/*---------------------------------------------------------------------- | PLT_EventSubscriber::Notify +---------------------------------------------------------------------*/ NPT_Result PLT_EventSubscriber::Notify(NPT_List<PLT_StateVariable*>& vars) { // verify we have eventable variables bool foundVars = false; NPT_XmlElementNode* propertyset = new NPT_XmlElementNode("e", "propertyset"); NPT_CHECK_SEVERE(propertyset->SetNamespaceUri( "e", "urn:schemas-upnp-org:event-1-0")); NPT_List<PLT_StateVariable*>::Iterator var = vars.GetFirstItem(); while (var) { if ((*var)->IsSendingEvents()) { NPT_XmlElementNode* property = new NPT_XmlElementNode("e", "property"); propertyset->AddChild(property); PLT_XmlHelper::AddChildText(property, (*var)->GetName(), (*var)->GetValue()); foundVars = true; } ++var; } // no eventable state variables found! if (foundVars == false) { delete propertyset; return NPT_FAILURE; } // format the body with the xml NPT_String xml; if (NPT_FAILED(PLT_XmlHelper::Serialize(*propertyset, xml))) { delete propertyset; NPT_CHECK_FATAL(NPT_FAILURE); } delete propertyset; // parse the callback url NPT_HttpUrl url(m_CallbackURLs[0]); if (!url.IsValid()) { NPT_CHECK_FATAL(NPT_FAILURE); } // format request NPT_HttpRequest* request = new NPT_HttpRequest(url, "NOTIFY", NPT_HTTP_PROTOCOL_1_1); NPT_HttpEntity* entity; PLT_HttpHelper::SetBody(*request, xml, &entity); // add the extra headers entity->SetContentType("text/xml; charset=\"utf-8\""); PLT_UPnPMessageHelper::SetNT(*request, "upnp:event"); PLT_UPnPMessageHelper::SetNTS(*request, "upnp:propchange"); PLT_UPnPMessageHelper::SetSID(*request, m_SID); PLT_UPnPMessageHelper::SetSeq(*request, m_EventKey); // wrap around sequence to 1 if (++m_EventKey == 0) m_EventKey = 1; // start the task now if not started already if (!m_SubscriberTask) { // TODO: the subscriber task should inform subscriber if // a notification failed to be received so it can be removed // from the list of subscribers inside the device host m_SubscriberTask = new PLT_HttpClientSocketTask(request, true); // short connection time out in case subscriber is not alive NPT_HttpClient::Config config; config.m_ConnectionTimeout = 2000; m_SubscriberTask->SetHttpClientConfig(config); // add initial delay to make sure ctrlpoint receives response to subscription // before our first NOTIFY. Also make sure task is not auto-destroy // since we want to destroy it manually when the subscriber goes away. NPT_TimeInterval delay(0.05f); NPT_CHECK_FATAL(m_TaskManager->StartTask(m_SubscriberTask, NULL /*&delay*/, false)); } else { m_SubscriberTask->AddRequest(request); } return NPT_SUCCESS; }
/*---------------------------------------------------------------------- | TestNamespaces +---------------------------------------------------------------------*/ static void TestNamespaces() { NPT_XmlElementNode* top = new NPT_XmlElementNode("top"); top->SetNamespaceUri("", "http://namespace1.com"); CHECK(top->GetNamespaceUri("") && *(top->GetNamespaceUri("")) == "http://namespace1.com"); NPT_XmlElementNode* child1 = new NPT_XmlElementNode("child1"); top->AddChild(child1); CHECK(child1->GetNamespaceUri("")); CHECK(*(child1->GetNamespaceUri("")) == "http://namespace1.com"); NPT_XmlElementNode* child2 = new NPT_XmlElementNode("ns1", "child2"); top->AddChild(child2); CHECK(child2->GetNamespaceUri("")); CHECK(*(child2->GetNamespaceUri("")) == "http://namespace1.com"); CHECK(child2->GetNamespaceUri("ns1") == NULL); child2->SetNamespaceUri("ns1", "http://blabla"); CHECK(child2->GetNamespaceUri("ns1")); CHECK(*child2->GetNamespaceUri("ns1") == "http://blabla"); CHECK(*child2->GetNamespace() == "http://blabla"); // testing a child with a namespace defined in parent NPT_XmlElementNode* child3 = new NPT_XmlElementNode("ns1", "child3"); child2->AddChild(child3); CHECK(child3->GetNamespaceUri("")); CHECK(*(child3->GetNamespaceUri("")) == "http://namespace1.com"); CHECK(child3->GetNamespaceUri("ns1")); CHECK(*child3->GetNamespaceUri("ns1") == "http://blabla"); CHECK(*child3->GetNamespace() == "http://blabla"); // testing adding a namespace in a node which namespace is defined in parent child3->SetNamespaceUri("ns3", "http://foofoo"); CHECK(child3->GetNamespaceUri("ns1")); CHECK(*child3->GetNamespaceUri("ns1") == "http://blabla"); CHECK(*child3->GetNamespace() == "http://blabla"); const char* xml1 = "<top>" " <child1 xmlns:foo='blabla'><cc1 foo:attr1='0'/></child1>" " <child2 xmlns='foobar' attr1='1'>" " <cc2/>" " <cc3 />" " </child2 >" " <ns2:child3 xmlns:ns2='abcd'><cc3/></ns2:child3>" " <child4 ns3:attr1='3' xmlns:ns3='efgh'>" " <ns3:cc4 ns3:attr1='4'/>" " </child4>" "</top>"; NPT_XmlParser parser; NPT_XmlNode* root = NULL; NPT_Result result = parser.Parse(xml1, root); CHECK(NPT_SUCCEEDED(result)); CHECK(root != NULL); NPT_XmlWriter writer; NPT_MemoryStream output; writer.Serialize(*root, output); NPT_LargeSize size; output.GetSize(size); printf(NPT_String((const char*)output.GetData(), (NPT_Size)size).GetChars()); delete top; delete root; // test default and empty namespaces const char* xml2 = "<top><a></a><b xmlns='foo'><c xmlns=''></c></b></top>"; result = parser.Parse(xml2, root); CHECK(root->AsElementNode()->GetNamespace() == NULL); NPT_XmlElementNode* a_elem = (*root->AsElementNode()->GetChildren().GetItem(0))->AsElementNode(); CHECK(a_elem->GetNamespace() == NULL); NPT_XmlElementNode* b_elem = (*root->AsElementNode()->GetChildren().GetItem(1))->AsElementNode(); CHECK(*b_elem->GetNamespace() == "foo"); NPT_XmlElementNode* c_elem = (*b_elem->GetChildren().GetItem(0))->AsElementNode(); CHECK(c_elem->GetNamespace() == NULL); delete root; }
/*---------------------------------------------------------------------- | CMediaCrawler::UpdateDidl +---------------------------------------------------------------------*/ NPT_String CMediaCrawler::UpdateDidl(const char* server_uuid, const NPT_String& didl, NPT_SocketInfo* info) { NPT_String new_didl; NPT_String str; NPT_XmlNode* node = NULL; NPT_XmlWriter writer; NPT_OutputStreamReference stream(new NPT_StringOutputStream(&new_didl)); NPT_LOG_FINE("Parsing Didl..."); NPT_XmlElementNode* tree = NULL; NPT_XmlParser parser; if (NPT_FAILED(parser.Parse(didl, node)) || !node || !node->AsElementNode()) { goto cleanup; } tree = node->AsElementNode(); NPT_LOG_FINE("Processing Didl xml..."); if (tree->GetTag().Compare("DIDL-Lite", true)) { goto cleanup; } // iterate through children NPT_Result res; for (NPT_List<NPT_XmlNode*>::Iterator children = tree->GetChildren().GetFirstItem(); children; children++) { NPT_XmlElementNode* child = (*children)->AsElementNode(); if (!child) continue; // object id remapping NPT_XmlAttribute* attribute_id; res = PLT_XmlHelper::GetAttribute(child, "id", attribute_id); if (NPT_SUCCEEDED(res) && attribute_id) { attribute_id->SetValue(FormatObjectId(server_uuid, attribute_id->GetValue())); } // parent ID remapping NPT_XmlAttribute* attribute_parent_id; res = PLT_XmlHelper::GetAttribute(child, "parentID", attribute_parent_id); if (NPT_SUCCEEDED(res)) { attribute_parent_id->SetValue(attribute_parent_id->GetValue().Compare("-1")?FormatObjectId(server_uuid, attribute_parent_id->GetValue()):"0"); } // resources remapping NPT_Array<NPT_XmlElementNode*> res; PLT_XmlHelper::GetChildren(child, res, "res"); if (res.GetItemCount() > 0) { for (unsigned int i=0; i<res.GetItemCount(); i++) { NPT_XmlElementNode* resource = res[i]; NPT_XmlAttribute* attribute_prot; const NPT_String* url; if (NPT_SUCCEEDED(PLT_XmlHelper::GetAttribute(resource, "protocolInfo", attribute_prot)) && (url = resource->GetText())) { // special case for Windows Media Connect // When a browse is done on the same machine, WMC uses localhost // instead of the IP for all resources urls which means we cannot advertise that // since it would be useless for a remote device // so we try to replace it with the right IP address by looking at which interface we received the // initial browse request on to make sure the remote device will be able to access the modified resource // urls (in case the local PC has more than 1 NICs) // replace the url NPT_List<NPT_XmlNode*>& children = resource->GetChildren(); NPT_HttpUrl http_url(NPT_Uri::PercentDecode(*url)); if ((http_url.GetHost() == "localhost" || http_url.GetHost() == "127.0.0.1") && info) { if (info->local_address.GetIpAddress().AsLong()) { http_url.SetHost(info->local_address.GetIpAddress().ToString()); // replace text children.Apply(NPT_ObjectDeleter<NPT_XmlNode>()); children.Clear(); resource->AddText(http_url.ToString()); url = resource->GetText(); } } CStreamHandler* handler = NULL; NPT_Result res = NPT_ContainerFind(m_StreamHandlers, CStreamHandlerFinder(attribute_prot->GetValue(), *url), handler); if (NPT_SUCCEEDED(res)) { handler->ModifyResource(resource); } } } } } // serialize modified node into new didl writer.Serialize(*node, *stream); delete node; return new_didl; cleanup: delete node; return didl; }
/*---------------------------------------------------------------------- | PLT_MediaController::OnEventNotify +---------------------------------------------------------------------*/ NPT_Result PLT_MediaController::OnEventNotify(PLT_Service* service, NPT_List<PLT_StateVariable*>* vars) { if (m_Listener) { // parse LastChange var into smaller vars PLT_StateVariable* lastChangeVar = NULL; if (NPT_SUCCEEDED(NPT_ContainerFind(*vars, PLT_ListStateVariableNameFinder("LastChange"), lastChangeVar))) { vars->Remove(lastChangeVar); PLT_Service* var_service = lastChangeVar->GetService(); NPT_String text = lastChangeVar->GetValue(); NPT_XmlNode* xml = NULL; NPT_XmlParser parser; if (NPT_FAILED(parser.Parse(text, xml)) || !xml || !xml->AsElementNode()) { delete xml; return NPT_FAILURE; } NPT_XmlElementNode* node = xml->AsElementNode(); if (!node->GetTag().Compare("Event", true)) { // look for the instance with attribute id = 0 NPT_XmlElementNode* instance = NULL; for (NPT_Cardinal i=0; i<node->GetChildren().GetItemCount(); i++) { NPT_XmlElementNode* child; if (NPT_FAILED(PLT_XmlHelper::GetChild(node, child, i))) continue; if (!child->GetTag().Compare("InstanceID", true)) { // extract the "val" attribute value NPT_String value; if (NPT_SUCCEEDED(PLT_XmlHelper::GetAttribute(child, "val", value)) && !value.Compare("0")) { instance = child; break; } } } // did we find an instance with id = 0 ? if (instance != NULL) { // all the children of the Instance node are state variables for (NPT_Cardinal j=0; j<instance->GetChildren().GetItemCount(); j++) { NPT_XmlElementNode* var_node; if (NPT_FAILED(PLT_XmlHelper::GetChild(instance, var_node, j))) continue; // look for the state variable in this service const NPT_String* value = var_node->GetAttribute("val"); PLT_StateVariable* var = var_service->FindStateVariable(var_node->GetTag()); if (value != NULL && var != NULL) { // get the value and set the state variable // if it succeeded, add it to the list of vars we'll event if (NPT_SUCCEEDED(var->SetValue(*value, false))) { vars->Add(var); NPT_LOG_FINE_2("PLT_MediaController received var change for (%s): %s", (const char*)var->GetName(), (const char*)var->GetValue()); } } } } } delete xml; } if (vars->GetItemCount()) { m_Listener->OnMRStateVariablesChanged(service, vars); } } return NPT_SUCCESS; }
/*---------------------------------------------------------------------- | PLT_Didl::FromDidl +---------------------------------------------------------------------*/ NPT_Result PLT_Didl::FromDidl(const char* xml, PLT_MediaObjectListReference& objects) { NPT_String str; PLT_MediaObject* object = NULL; NPT_XmlNode* node = NULL; NPT_XmlElementNode* didl = NULL; NPT_XmlParser parser; NPT_LOG_FINE("Parsing Didl..."); NPT_CHECK_LABEL_SEVERE(parser.Parse(xml, node), cleanup); if (!node || !node->AsElementNode()) { NPT_LOG_SEVERE("Invalid node type"); goto cleanup; } didl = node->AsElementNode(); if (didl->GetTag().Compare("DIDL-Lite", true)) { NPT_LOG_SEVERE("Invalid node tag"); goto cleanup; } // create entry list objects = new PLT_MediaObjectList(); // for each child, find out if it's a container or not // and then invoke the FromDidl on it for (NPT_List<NPT_XmlNode*>::Iterator children = didl->GetChildren().GetFirstItem(); children; children++) { NPT_XmlElementNode* child = (*children)->AsElementNode(); if (!child) continue; if (child->GetTag().Compare("Container", true) == 0) { object = new PLT_MediaContainer(); } else if (child->GetTag().Compare("item", true) == 0) { object = new PLT_MediaItem(); } else { NPT_LOG_WARNING("Invalid node tag"); continue; } if (NPT_FAILED(object->FromDidl(child))) { NPT_LOG_WARNING_1("Invalid didl for object: %s", (const char*) PLT_XmlHelper::Serialize(*child, false)); continue; } objects->Add(object); object = NULL; // reset to make sure it doesn't get deleted twice in case of error } delete node; return NPT_SUCCESS; cleanup: objects = NULL; delete node; delete object; return NPT_FAILURE; }
/*---------------------------------------------------------------------- | TestSerializer +---------------------------------------------------------------------*/ static void TestSerializer() { NPT_XmlWriter writer; NPT_MemoryStream output; NPT_String check; NPT_LargeSize size; // // test without namespaces // // simple element with no prefix and no namespace NPT_XmlElementNode* top = new NPT_XmlElementNode("top"); writer.Serialize(*top, output); output.GetSize(size); check.Assign((const char*)output.GetData(), (NPT_Size)size); CHECK(check == "<top/>"); // with one attribute output.SetSize(0); top->SetAttribute("attr1", "b&w"); writer.Serialize(*top, output); output.GetSize(size); check.Assign((const char*)output.GetData(), (NPT_Size)size); CHECK(check == "<top attr1=\"b&w\"/>"); // add one child output.SetSize(0); delete top; top = new NPT_XmlElementNode("top"); NPT_XmlElementNode* child1 = new NPT_XmlElementNode("child1"); top->AddChild(child1); writer.Serialize(*top, output); output.GetSize(size); check.Assign((const char*)output.GetData(), (NPT_Size)size); CHECK(check == "<top><child1/></top>"); // // test with namespaces // // test default namespaces output.SetSize(0); delete top; top = new NPT_XmlElementNode("top"); top->SetNamespaceUri("", "http://namespace.com"); writer.Serialize(*top, output); output.GetSize(size); check.Assign((const char*)output.GetData(), (NPT_Size)size); CHECK(check == "<top xmlns=\"http://namespace.com\"/>"); // test attribute prefixes output.SetSize(0); delete top; top = new NPT_XmlElementNode("top"); top->SetAttribute(NULL, "foo", "6"); top->SetAttribute("ns1", "foo", "3"); top->SetAttribute("ns2", "foo", "4"); top->SetAttribute("ns1", "foo", "5"); writer.Serialize(*top, output); output.GetSize(size); check.Assign((const char*)output.GetData(), (NPT_Size)size); CHECK(check == "<top foo=\"6\" ns1:foo=\"5\" ns2:foo=\"4\"/>"); delete top; }