Beispiel #1
0
/*----------------------------------------------------------------------
|   PLT_MediaBrowser::OnSearchResponse
+---------------------------------------------------------------------*/
NPT_Result
PLT_MediaBrowser::OnSearchResponse(NPT_Result               res, 
                                   PLT_DeviceDataReference& device, 
                                   PLT_ActionReference&     action, 
                                   void*                    userdata)
{
    NPT_String     value;
    PLT_BrowseInfo info;
    NPT_String     unescaped;

    if (NPT_FAILED(res) || action->GetErrorCode() != 0) {
        goto bad_action;
    }

    if (NPT_FAILED(action->GetArgumentValue("ContainerId", info.object_id)))  {
        goto bad_action;
    }
    if (NPT_FAILED(action->GetArgumentValue("UpdateID", value)) || 
        value.GetLength() == 0 || 
        NPT_FAILED(value.ToInteger(info.uid))) {
        goto bad_action;
    }
    if (NPT_FAILED(action->GetArgumentValue("NumberReturned", value)) || 
        value.GetLength() == 0 || 
        NPT_FAILED(value.ToInteger(info.nr))) {
        goto bad_action;
    }
    if (NPT_FAILED(action->GetArgumentValue("TotalMatches", value)) || 
        value.GetLength() == 0 || 
        NPT_FAILED(value.ToInteger(info.tm))) {
        goto bad_action;
    }
    if (NPT_FAILED(action->GetArgumentValue("Result", value)) || 
        value.GetLength() == 0) {
        goto bad_action;
    }
    
    if (NPT_FAILED(PLT_Didl::FromDidl(value, info.items))) {
        goto bad_action;
    }

    if (m_Delegate) m_Delegate->OnSearchResult(NPT_SUCCESS, device, &info, userdata);
    return NPT_SUCCESS;

bad_action:
    if (m_Delegate) m_Delegate->OnSearchResult(NPT_FAILURE, device, NULL, userdata);
    return NPT_FAILURE;
}
Beispiel #2
0
/*----------------------------------------------------------------------
|   PLT_MediaContainer::FromDidl
+---------------------------------------------------------------------*/
NPT_Result
PLT_MediaContainer::FromDidl(NPT_XmlElementNode* entry)
{
    NPT_String str;

    /* reset first */
    Reset();

    // check entry type
    if (entry->GetTag().Compare("Container", true) != 0) 
        return NPT_ERROR_INTERNAL;

    // check if item is searchable (is default true?)
    if (NPT_SUCCEEDED(PLT_XmlHelper::GetAttribute(entry, "searchable", str, "", 5))) {
        m_Searchable = PLT_Service::IsTrue(str);
    }

    // look for childCount
    if (NPT_SUCCEEDED(PLT_XmlHelper::GetAttribute(entry, "childCount", str, "", 256))) {
        NPT_UInt32 count;
        NPT_CHECK_SEVERE(str.ToInteger(count));
        m_ChildrenCount = count;
    }

	// upnp:searchClass child elements
    NPT_Array<NPT_XmlElementNode*> children;
	PLT_XmlHelper::GetChildren(entry, children, "upnp:searchClass");

    for (NPT_Cardinal i=0; i<children.GetItemCount(); i++) {
        PLT_SearchClass search_class;

        // extract url
        if (children[i]->GetText() == NULL) {
            NPT_LOG_WARNING_1("No searchClass text found in: %s", 
				(const char*)PLT_XmlHelper::Serialize(*children[i]));
			continue;
        }
		
        // DLNA 7.3.17.4
		search_class.type = children[i]->GetText()->SubString(0, 256);

		// extract optional attribute name
		PLT_XmlHelper::GetAttribute(children[i], "name", search_class.friendly_name);
		    
		// includeDerived property
		if (NPT_FAILED(PLT_XmlHelper::GetAttribute(children[i], "includeDerived", str))) {
            NPT_LOG_WARNING_1("No required attribute searchClass@includeDerived found in: %s", 
				(const char*)PLT_XmlHelper::Serialize(*children[i]));
			continue;
		}

		search_class.include_derived = PLT_Service::IsTrue(str);
		m_SearchClasses.Add(search_class);
	}

    return PLT_MediaObject::FromDidl(entry);
}
/*----------------------------------------------------------------------
|   NPT_LogConsoleHandler::Create
+---------------------------------------------------------------------*/
NPT_Result
NPT_LogConsoleHandler::Create(const char*      logger_name,
                              NPT_LogHandler*& handler)
{
    /* compute a prefix for the configuration of this handler */
    NPT_String logger_prefix = logger_name;
    logger_prefix += ".ConsoleHandler";

    /* allocate a new object */
    NPT_LogConsoleHandler* instance = new NPT_LogConsoleHandler();
    handler = instance;

    /* configure the object */
    NPT_String* colors;
    instance->m_UseColors = NPT_LOG_CONSOLE_HANDLER_DEFAULT_COLOR_MODE;
    colors = LogManager.GetConfigValue(logger_prefix,".colors");
    if (colors) {
        if (NPT_LogManager::ConfigValueIsBooleanTrue(*colors)) {
            instance->m_UseColors = true;
        } else if (NPT_LogManager::ConfigValueIsBooleanFalse(*colors)) {
            instance->m_UseColors = false;
        }
    }

    NPT_String* outputs;
    instance->m_Outputs = OUTPUT_TO_DEBUG;
    outputs = LogManager.GetConfigValue(logger_prefix,".outputs");
    if (outputs) {
        outputs->ToInteger(instance->m_Outputs, true);
    }

    NPT_String* filter;
    instance->m_FormatFilter = 0;
    filter = LogManager.GetConfigValue(logger_prefix,".filter");
    if (filter) {
        filter->ToInteger(instance->m_FormatFilter, true);
    }

    return NPT_SUCCESS;
}
Beispiel #4
0
/*----------------------------------------------------------------------
|   PLT_HttpHelper::GetContentLength
+---------------------------------------------------------------------*/
NPT_Result
PLT_HttpHelper::GetContentLength(NPT_HttpMessage* message, NPT_Size& len) 
{ 
    long out;
    NPT_String value;
    if (NPT_FAILED(message->GetHeaders().GetHeaderValue(NPT_HTTP_HEADER_CONTENT_LENGTH, value))) {
        return NPT_FAILURE;
    }

    NPT_Result res = value.ToInteger(out);
    len = out;
    return res;
}
Beispiel #5
0
/*----------------------------------------------------------------------
|   PLT_Didl::ParseTimeStamp
+---------------------------------------------------------------------*/
NPT_Result
PLT_Didl::ParseTimeStamp(const NPT_String& timestamp, NPT_UInt32& seconds)
{
    // assume a timestamp in the format HH:MM:SS.FFF
    int separator;
    NPT_String str = timestamp;
    NPT_UInt32 value;

    // reset output params first
    seconds = 0;
    
    // remove milliseconds first if any
    if ((separator = str.ReverseFind('.')) != -1) {
        str = str.Left(separator);
    }

    // look for next separator
    if ((separator = str.ReverseFind(':')) == -1) return NPT_FAILURE;
    
    // extract seconds
    NPT_CHECK_WARNING(str.SubString(separator+1).ToInteger(value));
    seconds = value;
    str = str.Left(separator);

    // look for next separator
    if ((separator = str.ReverseFind(':')) == -1) return NPT_FAILURE;
    
    // extract minutes
    NPT_CHECK_WARNING(str.SubString(separator+1).ToInteger(value));
    seconds += 60*value;
    str = str.Left(separator);
    
    // extract hours
    NPT_CHECK_WARNING(str.ToInteger(value));
    seconds += 3600*value;
    
    return NPT_SUCCESS;
}
Beispiel #6
0
/*----------------------------------------------------------------------
|   PLT_FileMediaServer::OnBrowseDirectChildren
+---------------------------------------------------------------------*/
NPT_Result
PLT_FileMediaServer::OnBrowseDirectChildren(PLT_ActionReference&          action, 
                                            const char*                   object_id, 
                                            const NPT_HttpRequestContext& context)
{
    /* locate the file from the object ID */
    NPT_String dir;
    if (NPT_FAILED(GetFilePath(object_id, dir))) {
        /* error */
        NPT_LOG_WARNING("PLT_FileMediaServer::OnBrowse - ObjectID not found.");
        action->SetError(701, "No Such Object.");
        return NPT_FAILURE;
    }

    /* retrieve the item type */
    NPT_FileInfo info;
    NPT_Result res = NPT_File::GetInfo(dir, &info);
    if (NPT_FAILED(res)) {
        /* Object does not exist */
        NPT_LOG_WARNING_1("PLT_FileMediaServer::OnBrowse - BROWSEDIRECTCHILDREN failed for item %s", dir.GetChars());
        action->SetError(800, "Can't retrieve info " + dir);
        return NPT_FAILURE;
    }

    if (info.m_Type != NPT_FileInfo::FILE_TYPE_DIRECTORY) {
        /* error */
        NPT_LOG_WARNING("PLT_FileMediaServer::OnBrowse - BROWSEDIRECTCHILDREN not allowed on an item.");
        action->SetError(710, "item is not a container.");
        return NPT_FAILURE;
    }

    NPT_String filter;
    NPT_String startingInd;
    NPT_String reqCount;

    NPT_CHECK_SEVERE(action->GetArgumentValue("Filter", filter));
    NPT_CHECK_SEVERE(action->GetArgumentValue("StartingIndex", startingInd));
    NPT_CHECK_SEVERE(action->GetArgumentValue("RequestedCount", reqCount));   

    NPT_UInt32 start_index, req_count;
    if (NPT_FAILED(startingInd.ToInteger(start_index)) ||
        NPT_FAILED(reqCount.ToInteger(req_count))) {        
        action->SetError(412, "Precondition failed");
        return NPT_FAILURE;
    }

    NPT_List<NPT_String> entries;
    res = NPT_File::ListDirectory(dir, entries, 0, 0);
    if (NPT_FAILED(res)) {
        NPT_LOG_WARNING_1("PLT_FileMediaServer::OnBrowseDirectChildren - failed to open dir %s", (const char*) dir);
        return res;
    }

    unsigned long cur_index = 0;
    unsigned long num_returned = 0;
    unsigned long total_matches = 0;
    NPT_String didl = didl_header;

    PLT_MediaObjectReference item;
    for (NPT_List<NPT_String>::Iterator it = entries.GetFirstItem();
        it;
        ++it) {
        NPT_String& filename = *it;
        item = BuildFromFilePath(
            NPT_FilePath::Create(dir, filename), 
            true, 
            &context.GetLocalAddress());

        if (!item.IsNull()) {
            if ((cur_index >= start_index) && ((num_returned < req_count) || (req_count == 0))) {
                NPT_String tmp;
                NPT_CHECK_SEVERE(PLT_Didl::ToDidl(*item.AsPointer(), filter, tmp));

                didl += tmp;
                num_returned++;
            }
            cur_index++;
            total_matches++;        
        }
    };

    didl += didl_footer;

    NPT_CHECK_SEVERE(action->SetArgumentValue("Result", didl));
    NPT_CHECK_SEVERE(action->SetArgumentValue("NumberReturned", NPT_String::FromInteger(num_returned)));
    NPT_CHECK_SEVERE(action->SetArgumentValue("TotalMatches", NPT_String::FromInteger(total_matches))); // 0 means we don't know how many we have but most browsers don't like that!!
    NPT_CHECK_SEVERE(action->SetArgumentValue("UpdateId", "1"));

    return NPT_SUCCESS;
}
/*----------------------------------------------------------------------
|   NPT_LogFileHandler::Create
+---------------------------------------------------------------------*/
NPT_Result
NPT_LogFileHandler::Create(const char*      logger_name,
                           NPT_LogHandler*& handler)
{
    /* compute a prefix for the configuration of this handler */
    NPT_String logger_prefix = logger_name;
    logger_prefix += ".FileHandler";

    /* allocate a new object */
    NPT_LogFileHandler* instance = new NPT_LogFileHandler();
    handler = instance;

    /* filename */
    NPT_String* filename_conf = LogManager.GetConfigValue(logger_prefix, ".filename");
    if (filename_conf) {
        instance->m_Filename = *filename_conf;
    } else if (logger_name[0]) {
        NPT_String filename_synth = logger_name;
        filename_synth += ".log";
        instance->m_Filename = filename_synth;
    } else {
        /* default name for the root logger */
        instance->m_Filename = NPT_CONFIG_DEFAULT_LOG_FILE_HANDLER_FILENAME;
    }

    /* always flush flag */
    NPT_String* flush = LogManager.GetConfigValue(logger_prefix, ".flush");
    if (flush && NPT_LogManager::ConfigValueIsBooleanTrue(*flush)) {
        instance->m_Flush = true;
    } else {
        instance->m_Flush = false;
    }

    /* append mode */
    instance->m_Append = true;
    NPT_String* append_mode = LogManager.GetConfigValue(logger_prefix, ".append");
    if (append_mode && NPT_LogManager::ConfigValueIsBooleanFalse(*append_mode)) {
        instance->m_Append = false;
    }

    /* filter */
    NPT_String* filter;
    instance->m_FormatFilter = 0;
    filter = LogManager.GetConfigValue(logger_prefix,".filter");
    if (filter) {
        filter->ToInteger(instance->m_FormatFilter, true);
    }

    /* recycle */
    NPT_String* recycle;
    instance->m_MaxFilesize = 0;
    recycle = LogManager.GetConfigValue(logger_prefix,".recycle");
    if (recycle) {
        NPT_ParseInteger64(*recycle, instance->m_MaxFilesize, true);
        if (instance->m_MaxFilesize < NPT_LOG_FILE_HANDLER_MIN_RECYCLE_SIZE) {
            instance->m_MaxFilesize = NPT_LOG_FILE_HANDLER_MIN_RECYCLE_SIZE;
        }
    }

    /* open the log file */
    return instance->Open(instance->m_Append);
}
Beispiel #8
0
/*----------------------------------------------------------------------
|   PLT_MediaServer::OnSearch
+---------------------------------------------------------------------*/
NPT_Result
PLT_MediaServer::OnSearch(PLT_ActionReference&          action, 
                          const PLT_HttpRequestContext& context)
{
    NPT_COMPILER_UNUSED(context);

    NPT_Result res;
    NPT_String container_id;
    NPT_String search;
	NPT_String filter;
    NPT_String start;
    NPT_String count;
    NPT_String sort;
    NPT_List<NPT_String> sort_list;

    if (NPT_FAILED(action->GetArgumentValue("ContainerId", container_id)) ||
        NPT_FAILED(action->GetArgumentValue("SearchCriteria", search)) || 
		NPT_FAILED(action->GetArgumentValue("Filter",  filter)) ||
        NPT_FAILED(action->GetArgumentValue("StartingIndex",  start)) || 
        NPT_FAILED(action->GetArgumentValue("RequestedCount",  count)) || 
        NPT_FAILED(action->GetArgumentValue("SortCriteria",  sort))) {
        NPT_LOG_WARNING("Missing arguments");
        action->SetError(402, "Invalid args");
        return NPT_SUCCESS;
    }
    
    /* convert index and counts to int */
    NPT_UInt32 starting_index, requested_count;
    if (NPT_FAILED(start.ToInteger(starting_index)) ||
        NPT_FAILED(count.ToInteger(requested_count))) {       
        NPT_LOG_WARNING_2("Invalid arguments (%s, %s)", 
            start.GetChars(), count.GetChars());
        action->SetError(402, "Invalid args");
        return NPT_FAILURE;
    }
    
    /* parse sort criteria */
    if (NPT_FAILED(ParseSort(sort, sort_list))) {
        NPT_LOG_WARNING_1("Unsupported or invalid sort criteria error (%s)", 
            sort.GetChars());
        action->SetError(709, "Unsupported or invalid sort criteria error");
        return NPT_FAILURE;
    }
    
    NPT_LOG_INFO_5("Processing Search from %s with id=\"%s\", search=\"%s\", start=%d, count=%d", 
                   (const char*)context.GetRemoteAddress().GetIpAddress().ToString(),
                   (const char*)container_id,
                   (const char*)search,
                   starting_index,
                   requested_count);
                       
    if (search.IsEmpty() || search == "*") {
        res = OnBrowseDirectChildren(
            action, 
            container_id,
			filter,
            starting_index, 
            requested_count, 
            sort, 
            context);
    } else {
        res = OnSearchContainer(
            action, 
            container_id, 
            search, 
			filter,
            starting_index, 
            requested_count, 
            sort,
            context);
    }

    if (NPT_FAILED(res) && (action->GetErrorCode() == 0)) {
        action->SetError(800, "Internal error");
    }

    return res;
}
Beispiel #9
0
/*----------------------------------------------------------------------
|   PLT_MediaServer::OnBrowse
+---------------------------------------------------------------------*/
NPT_Result
PLT_MediaServer::OnBrowse(PLT_ActionReference&          action, 
                          const PLT_HttpRequestContext& context)
{
    NPT_Result res;
    NPT_String object_id;
    NPT_String browse_flag_val;    
    NPT_String filter;
    NPT_String start;
    NPT_String count;
    NPT_String sort;
    NPT_List<NPT_String> sort_list;

    if (NPT_FAILED(action->GetArgumentValue("ObjectId", object_id)) || 
        NPT_FAILED(action->GetArgumentValue("BrowseFlag",  browse_flag_val)) || 
        NPT_FAILED(action->GetArgumentValue("Filter",  filter)) || 
        NPT_FAILED(action->GetArgumentValue("StartingIndex",  start)) || 
        NPT_FAILED(action->GetArgumentValue("RequestedCount",  count)) || 
        NPT_FAILED(action->GetArgumentValue("SortCriteria",  sort))) {
        NPT_LOG_WARNING("Missing arguments");
        action->SetError(402, "Invalid args");
        return NPT_SUCCESS;
    }

    /* extract flag */
    BrowseFlags flag;
    if (NPT_FAILED(ParseBrowseFlag(browse_flag_val, flag))) {
        /* error */
        NPT_LOG_WARNING_1("BrowseFlag value not allowed (%s)", (const char*)browse_flag_val);
        action->SetError(402, "Invalid args");
        return NPT_SUCCESS;
    }
    
    /* convert index and counts to int */
    NPT_UInt32 starting_index, requested_count;
    if (NPT_FAILED(start.ToInteger(starting_index)) ||
        NPT_FAILED(count.ToInteger(requested_count)) ||
        PLT_Didl::ConvertFilterToMask(filter) == 0) {       
        NPT_LOG_WARNING_3("Invalid arguments (%s, %s, %s)", 
            start.GetChars(), count.GetChars(), filter.GetChars());
        action->SetError(402, "Invalid args");
        return NPT_FAILURE;
    }
    
    /* parse sort criteria for validation */
    if (NPT_FAILED(ParseSort(sort, sort_list))) {
        NPT_LOG_WARNING_1("Unsupported or invalid sort criteria error (%s)", 
            sort.GetChars());
        action->SetError(709, "Unsupported or invalid sort criteria error");
        return NPT_FAILURE;
    }
    
    NPT_LOG_FINE_6("Processing %s from %s with id=\"%s\", filter=\"%s\", start=%d, count=%d", 
                   (const char*)browse_flag_val, 
                   (const char*)context.GetRemoteAddress().GetIpAddress().ToString(),
                   (const char*)object_id,
                   (const char*)filter,
                   starting_index,
                   requested_count);

    /* Invoke the browse function */
    if (flag == BROWSEMETADATA) {
        res = OnBrowseMetadata(
            action, 
            object_id, 
            filter, 
            starting_index, 
            requested_count, 
            sort, 
            context);
    } else {
        res = OnBrowseDirectChildren(
            action, 
            object_id, 
            filter, 
            starting_index, 
            requested_count, 
            sort, 
            context);
    }

    if (NPT_FAILED(res) && (action->GetErrorCode() == 0)) {
        action->SetError(800, "Internal error");
    }

    return res;
}
Beispiel #10
0
/*----------------------------------------------------------------------
|   CMediaCrawler::OnBrowseDevice
+---------------------------------------------------------------------*/
NPT_Result
CMediaCrawler::OnBrowseDevice(PLT_ActionReference& action, 
                              const char*          server_uuid, 
                              const char*          server_object_id, 
                              NPT_SocketInfo*      info /* = NULL */)
{
    NPT_Result res;
    PLT_DeviceDataReference device;

    {
        // look for device first
        const NPT_Lock<PLT_DeviceDataReferenceList>& devices = GetMediaServers();
        //NPT_AutoLock lock(devices);

        if (NPT_FAILED(NPT_ContainerFind(devices, PLT_DeviceDataFinder(server_uuid), device))) {
            /* error */
            NPT_LOG_WARNING("CMediaCrawler::OnBrowseDevice - device not found.");
            action->SetError(701, "No Such Object.");
            return NPT_FAILURE;
        } 
    }

    // look for args and convert them
    NPT_String browseFlagValue;
    NPT_String startingInd;
    NPT_String reqCount;
    NPT_String filter;
    NPT_String sort;

    NPT_CHECK_SEVERE(action->GetArgumentValue("BrowseFlag", browseFlagValue));
    NPT_CHECK_SEVERE(action->GetArgumentValue("StartingIndex", startingInd));
    NPT_CHECK_SEVERE(action->GetArgumentValue("RequestedCount", reqCount));   
    NPT_CHECK_SEVERE(action->GetArgumentValue("Filter", filter));
    NPT_CHECK_SEVERE(action->GetArgumentValue("SortCriteria", sort));

    unsigned long start_index, req_count;
    if (NPT_FAILED(startingInd.ToInteger(start_index)) ||
        NPT_FAILED(reqCount.ToInteger(req_count))) {
        return NPT_FAILURE;
    } 

    // create a container for our result
    // this will be filled in by OnBrowseResponse
    CMediaCrawlerBrowseInfoReference browse_info(new CMediaCrawlerBrowseInfo());
    browse_info->shared_var.SetValue(0);

    // send off the browse packet.  Note that this will
    // not block.  The shared variable is used to block
    // until the response has been received.
    res = Browse(device,
        server_object_id,
        start_index,
        req_count,
        (browseFlagValue == "BrowseMetadata")?1:0,
        filter,
        sort,
        new CMediaCrawlerBrowseInfoReference(browse_info));		
    NPT_CHECK_SEVERE(res);

    // wait 30 secs for response
    res = browse_info->shared_var.WaitUntilEquals(1, 30000);
    NPT_CHECK_SEVERE(res);

    // did the browse fail?
    if (NPT_FAILED(browse_info->res)) {
        action->SetError(browse_info->code, "");
        return NPT_FAILURE;
    }    
   
    action->SetArgumentValue("Result", UpdateDidl(server_uuid, browse_info->didl, info));
    action->SetArgumentValue("NumberReturned", browse_info->nr);
    action->SetArgumentValue("TotalMatches", browse_info->tm);
    action->SetArgumentValue("UpdateId", browse_info->uid);
    action->SetArgumentValue("ObjectID", FormatObjectId(server_uuid, browse_info->object_id));
    
    return NPT_SUCCESS;
}
Beispiel #11
0
/*----------------------------------------------------------------------
|   CMediaCrawler::OnBrowseRoot
+---------------------------------------------------------------------*/
NPT_Result
CMediaCrawler::OnBrowseRoot(PLT_ActionReference& action)
{
    NPT_String browseFlagValue;
    if (NPT_FAILED(action->GetArgumentValue("BrowseFlag", browseFlagValue))) {
        NPT_LOG_WARNING("PLT_FileMediaServer::OnBrowse - invalid arguments.");
        return NPT_FAILURE;
    }

    /* extract browseFlag */
    BrowseFlags browseFlag;
    if (NPT_FAILED(GetBrowseFlag(browseFlagValue, browseFlag))) {
        /* error */
        NPT_LOG_WARNING("PLT_FileMediaServer::OnBrowseRoot - BrowseFlag value not allowed.");
        action->SetError(402,"Invalid BrowseFlag arg.");
        return NPT_FAILURE;
    }

    if (browseFlag == BROWSEMETADATA) {
        PLT_MediaContainer item;
        item.m_Title = "Root";
        item.m_ParentID = "-1";
        item.m_ObjectID = "0";
        item.m_ChildrenCount = GetMediaServers().GetItemCount();
        item.m_ObjectClass.type = "object.container";

        /* convert item to didl */
        NPT_String filter;
        action->GetArgumentValue("Filter", filter);
        NPT_String tmp;
        NPT_CHECK_SEVERE(PLT_Didl::ToDidl(item, filter, tmp));

        /* add didl header and footer */
        NPT_String didl = didl_header + tmp + didl_footer;

        action->SetArgumentValue("Result", didl);
        action->SetArgumentValue("NumberReturned", "1");
        action->SetArgumentValue("TotalMatches", "1");

        // update ID may be wrong here, it should be the one of the container?
        action->SetArgumentValue("UpdateId", "1");
        // TODO: We need to keep track of the overall updateID of the CDS
    } else {
        NPT_String startingInd;
        NPT_String reqCount;
        NPT_String filter;

        NPT_CHECK_SEVERE(action->GetArgumentValue("StartingIndex", startingInd));
        NPT_CHECK_SEVERE(action->GetArgumentValue("RequestedCount", reqCount));   
        NPT_CHECK_SEVERE(action->GetArgumentValue("Filter", filter));

        unsigned long start_index, req_count;
        if (NPT_FAILED(startingInd.ToInteger(start_index)) ||
            NPT_FAILED(reqCount.ToInteger(req_count))) {
            return NPT_FAILURE;
        }   
                    
        unsigned long cur_index = 0;
        unsigned long num_returned = 0;
        unsigned long total_matches = 0;
        //unsigned long update_id = 0;
        PLT_MediaContainer item;
        NPT_String tmp;
        NPT_String didl = didl_header;

        // populate a list of containers (one container per known servers)
        const NPT_Lock<PLT_DeviceDataReferenceList>& devices = GetMediaServers();
        NPT_Lock<PLT_DeviceDataReferenceList>::Iterator entry = devices.GetFirstItem();
        while (entry) {
            PLT_DeviceDataReference device = (*entry);
            item.m_Title = device->GetFriendlyName();
            item.m_ObjectID = FormatObjectId(device->GetUUID(), "0");
            item.m_ParentID = "0";
            item.m_ObjectClass.type = "object.container";

            if ((cur_index >= start_index) && ((num_returned < req_count) || (req_count == 0))) {
                NPT_CHECK_SEVERE(PLT_Didl::ToDidl(item, filter, tmp));

                didl += tmp;
                num_returned++;
            }
            cur_index++;
            total_matches++;  

            ++entry;
        }

        didl += didl_footer;

        action->SetArgumentValue("Result", didl);
        action->SetArgumentValue("NumberReturned", NPT_String::FromInteger(num_returned));
        action->SetArgumentValue("TotalMatches", NPT_String::FromInteger(total_matches));
        action->SetArgumentValue("UpdateId", "1");
    }

    return NPT_SUCCESS;
}
/*----------------------------------------------------------------------
|   PLT_FileMediaServer::OnBrowseDirectChildren
+---------------------------------------------------------------------*/
NPT_Result
PLT_FileMediaServer::OnBrowseDirectChildren(PLT_ActionReference& action, 
                                            const char*          object_id, 
                                            NPT_SocketInfo*      info /* = NULL */)
{
    /* locate the file from the object ID */
    NPT_String dir;
    if (NPT_FAILED(GetFilePath(object_id, dir))) {
        /* error */
        NPT_LOG_WARNING("PLT_FileMediaServer::OnBrowse - ObjectID not found.");
        action->SetError(701, "No Such Object.");
        return NPT_FAILURE;
    }

    /* retrieve the item type */
    NPT_DirectoryEntryInfo entry_info;
    NPT_Result res = NPT_DirectoryEntry::GetInfo(dir, entry_info);
    if (NPT_FAILED(res)) {
        /* Object does not exist */
        action->SetError(800, "Can't retrieve info " + dir);
        return NPT_FAILURE;
    }

    if (entry_info.type != NPT_DIRECTORY_TYPE) {
        /* error */
        NPT_LOG_WARNING("PLT_FileMediaServer::OnBrowse - BROWSEDIRECTCHILDREN not allowed on an item.");
        action->SetError(710, "item is not a container.");
        return NPT_FAILURE;
    }

    NPT_String filter;
    NPT_String startingInd;
    NPT_String reqCount;

    NPT_CHECK_SEVERE(action->GetArgumentValue("Filter", filter));
    NPT_CHECK_SEVERE(action->GetArgumentValue("StartingIndex", startingInd));
    NPT_CHECK_SEVERE(action->GetArgumentValue("RequestedCount", reqCount));   

    unsigned long start_index, req_count;
    if (NPT_FAILED(startingInd.ToInteger(start_index)) ||
        NPT_FAILED(reqCount.ToInteger(req_count))) {
        return NPT_FAILURE;
    }

    NPT_String path = dir;
    if (!path.EndsWith(m_DirDelimiter)) {
        path += m_DirDelimiter;
    }

    /* start iterating through the directory */
    NPT_Directory directory(path);
    NPT_String    entryName;
    res = directory.GetNextEntry(entryName);
    if (NPT_FAILED(res)) {
        NPT_LOG_WARNING_1("PLT_FileMediaServer::OnBrowseDirectChildren - failed to open dir %s", (const char*) path);
        return res;
    }

    unsigned long cur_index = 0;
    unsigned long num_returned = 0;
    unsigned long total_matches = 0;
    //unsigned long update_id = 0;
    NPT_String didl = didl_header;
    PLT_MediaObjectReference item;
    do {
        item = BuildFromFilePath(path + entryName, true, info);
        if (!item.IsNull()) {
            if ((cur_index >= start_index) && ((num_returned < req_count) || (req_count == 0))) {
                NPT_String tmp;
                NPT_CHECK_SEVERE(PLT_Didl::ToDidl(*item.AsPointer(), filter, tmp));

                didl += tmp;
                num_returned++;
            }
            cur_index++;
            total_matches++;        
        }
        res = directory.GetNextEntry(entryName);
    } while (NPT_SUCCEEDED(res));

    didl += didl_footer;

    NPT_CHECK_SEVERE(action->SetArgumentValue("Result", didl));

    NPT_CHECK_SEVERE(action->SetArgumentValue("NumberReturned", NPT_String::FromInteger(num_returned)));

    NPT_CHECK_SEVERE(action->SetArgumentValue("TotalMatches", NPT_String::FromInteger(total_matches)));

    NPT_CHECK_SEVERE(action->SetArgumentValue("UpdateId", "1"));

    return NPT_SUCCESS;
}