/*---------------------------------------------------------------------- | 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; }
/*---------------------------------------------------------------------- | TestAttributeNormalization +---------------------------------------------------------------------*/ static void TestAttributeNormalization() { const char* xml = "<x a='\n\n xyz abc 
 
 	   12\r\n3\r4\n5 6 '/>"; 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); const NPT_String* a = root->AsElementNode()->GetAttribute("a"); CHECK(*a == " xyz abc \r \n \t 12 3 4 5 6 "); delete root; }
/*---------------------------------------------------------------------- | TestAttributes +---------------------------------------------------------------------*/ static void TestAttributes() { const char* xml = "<element foo='blabla'><cc1 attr1='0'/></element>"; 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); const NPT_String* a = root->AsElementNode()->GetAttribute("foo"); CHECK(*a == "blabla"); delete root; }
/*---------------------------------------------------------------------- | 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_HttpHelper::ParseBody +---------------------------------------------------------------------*/ NPT_Result PLT_HttpHelper::ParseBody(const NPT_HttpMessage& message, NPT_XmlElementNode*& tree) { // reset tree tree = NULL; // read body NPT_String body; NPT_CHECK_WARNING(GetBody(message, body)); // parse body NPT_XmlParser parser; NPT_XmlNode* node; NPT_Result result = parser.Parse(body, node); if (NPT_FAILED(result)) { NPT_LOG_FINEST_1("Failed to parse %s", body.IsEmpty()?"(empty string)":body.GetChars()); NPT_CHECK_WARNING(result); } tree = node->AsElementNode(); if (!tree) { delete node; return NPT_FAILURE; } return NPT_SUCCESS; }
/*---------------------------------------------------------------------- | 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_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; }
/*---------------------------------------------------------------------- | 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_HttpHelper::ParseBody +---------------------------------------------------------------------*/ NPT_Result PLT_HttpHelper::ParseBody(NPT_HttpMessage* message, NPT_XmlElementNode*& tree) { // reset tree tree = NULL; // read body NPT_String body; NPT_CHECK_WARNING(GetBody(message, body)); // parse body NPT_XmlParser parser; NPT_XmlNode* node; NPT_CHECK_WARNING(parser.Parse(body, node)); tree = node->AsElementNode(); if (!tree) { delete node; return NPT_FAILURE; } 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; }
/*---------------------------------------------------------------------- | 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; }