/*----------------------------------------------------------------------
|   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;
}
Example #2
0
/*----------------------------------------------------------------------
|       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;
}
Example #4
0
/*----------------------------------------------------------------------
|       TestAttributeNormalization
+---------------------------------------------------------------------*/
static void
TestAttributeNormalization()
{
    const char* xml = "<x a='\n\n xyz abc &#xD; &#xA; &#x9; &#x20; 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;
}
Example #5
0
/*----------------------------------------------------------------------
|       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;
}
Example #6
0
/*----------------------------------------------------------------------
|   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;
}
Example #7
0
/*----------------------------------------------------------------------
|   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;
}
Example #8
0
/*----------------------------------------------------------------------
|       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;
}
Example #9
0
/*----------------------------------------------------------------------
|   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;
}
Example #10
0
/*----------------------------------------------------------------------
|   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;
}
Example #11
0
/*----------------------------------------------------------------------
|       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;
}
Example #12
0
/*----------------------------------------------------------------------
|   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;
}
Example #13
0
/*----------------------------------------------------------------------
|   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;
}