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