/*---------------------------------------------------------------------- | 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; }
/*---------------------------------------------------------------------- | 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; }
/*---------------------------------------------------------------------- | 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; }
/*---------------------------------------------------------------------- | 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; }
/*---------------------------------------------------------------------- | 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; }