/***************************************************************************** * ContentDir_GetSearchCapabilities *****************************************************************************/ const char* ContentDir_GetSearchCapabilities (ContentDir* self, void* unused) { if (self == NULL) return NULL; // ----------> // Send Action if result not already cached if (self->search_caps == NULL) { IXML_Document* doc = NULL; int rc = Service_SendActionVa (OBJECT_SUPER_CAST(self), &doc, "GetSearchCapabilities", NULL, NULL); if (rc == UPNP_E_SUCCESS && doc != NULL) { self->search_caps = talloc_strdup (self, XMLUtil_FindFirstElementValue (XML_D2N (doc), "SearchCaps", true, true)); Log_Printf (LOG_DEBUG, "ContentDir_GetSearchCapabilities = '%s'", NN(self->search_caps)); } ixmlDocument_free (doc); } return self->search_caps; }
int YX_CD_GetMetadata(pClassContentDirectory me, char *id, char **metadata) { int ret = -1; HT_DBG_FUNC_START(HT_MOD_DMC, HT_BIT_FEW,(int)me, id); me->SyncBrowseMetedata(me, id); if( me->nb_returned > 0) { const char *result = XMLUtil_FindFirstElementValue(XML_D2N (me->ActionResult), "Result", true, true); *metadata = Dlna_strdup(result); ret = 0; } HT_DBG_FUNC_END(ret, *metadata); return ret; }
/****************************************************************************** * BrowseAction *****************************************************************************/ static int BrowseOrSearchAction (ContentDir* cds, void* result_context, const char* objectId, const char* criteria, Index starting_index, Count requested_count, Count* nb_matched, Count* nb_returned, PtrArray* objects) { if (cds == NULL || objectId == NULL || criteria == NULL) { Log_Printf (LOG_ERROR, "BrowseOrSearchAction NULL parameter"); return UPNP_E_INVALID_PARAM; // ----------> } // Create a working context for temporary allocations void* tmp_ctx = talloc_new (NULL); const bool browse = is_browse (criteria); IXML_Document* doc = NULL; int rc = Service_SendActionVa (OBJECT_SUPER_CAST(cds), &doc, (browse ? "Browse" : "Search"), (browse ? "ObjectID" : "ContainerID"), objectId, (browse ? "BrowseFlag" : "SearchCriteria"), criteria, "Filter", "*", "StartingIndex", int_to_string (tmp_ctx, starting_index), "RequestedCount", int_to_string (tmp_ctx, requested_count), "SortCriteria", "", NULL, NULL); if (doc == NULL && rc == UPNP_E_SUCCESS) rc = UPNP_E_BAD_RESPONSE; if (rc != UPNP_E_SUCCESS) { Log_Printf (LOG_ERROR, "BrowseOrSearchAction ObjectId='%s'", NN(objectId)); goto cleanup; // ----------> } const char* s = XMLUtil_FindFirstElementValue (XML_D2N (doc), "TotalMatches", true, true); STRING_TO_INT (s, *nb_matched, 0); s = XMLUtil_FindFirstElementValue (XML_D2N (doc), "NumberReturned", true, true); STRING_TO_INT (s, *nb_returned, 0); Log_Printf (LOG_DEBUG, "+++BROWSE RESULT+++\n%s\n", XMLUtil_GetDocumentString (tmp_ctx, doc)); const char* const resstr = XMLUtil_FindFirstElementValue (XML_D2N (doc), "Result", true, true); if (resstr == NULL) { Log_Printf (LOG_ERROR, "BrowseOrSearchAction ObjectId=%s : " "can't get 'Result' in doc=%s", objectId, XMLUtil_GetDocumentString (tmp_ctx, doc)); rc = UPNP_E_BAD_RESPONSE; goto cleanup; // ----------> } IXML_Document* const subdoc = ixmlParseBuffer (discard_const_p (char, resstr)); if (subdoc == NULL) { Log_Printf (LOG_ERROR, "BrowseOrSearchAction ObjectId=%s : " "can't parse 'Result'=%s", objectId, resstr); rc = UPNP_E_BAD_RESPONSE; } else { IXML_NodeList* containers = ixmlDocument_getElementsByTagName (subdoc, "container"); ContentDir_Count const nb_containers = ixmlNodeList_length (containers); IXML_NodeList* items = ixmlDocument_getElementsByTagName (subdoc, "item"); ContentDir_Count const nb_items = ixmlNodeList_length (items); if (nb_containers + nb_items != *nb_returned) { Log_Printf (LOG_ERROR, "BrowseOrSearchAction ObjectId=%s " "got %d containers + %d items, " "expected %d", objectId, (int) nb_containers, (int) nb_items, (int) *nb_returned); *nb_returned = nb_containers + nb_items; } if (criteria == CRITERIA_BROWSE_METADATA && *nb_returned != 1){ Log_Printf (LOG_ERROR, "ContentDir_Browse Metadata : " "not 1 result exactly ! Id=%s", NN(objectId)); } ContentDir_Count i; for (i = 0; i < *nb_returned; i++) { bool const is_container = (i < nb_containers); IXML_Element* const elem = (IXML_Element*) ixmlNodeList_item (is_container ? containers : items, is_container ? i : i - nb_containers); DIDLObject* o = DIDLObject_Create (result_context, elem, is_container); if (o) { PtrArray_Append (objects, o); } } if (containers) ixmlNodeList_free (containers); if (items) ixmlNodeList_free (items); ixmlDocument_free (subdoc); } cleanup: ixmlDocument_free (doc); doc = NULL; // Delete all temporary storage talloc_free (tmp_ctx); tmp_ctx = NULL; if (rc != UPNP_E_SUCCESS) *nb_returned = *nb_matched = 0; return rc; }
static int s_ParseBrowseOrSearchResult (Upnp_EventType EventType, void *Event, void *cookie) { int kill = 0; pClassContentDirectory me = (pClassContentDirectory)cookie; struct Upnp_Action_Complete *pEvt = (struct Upnp_Action_Complete *)Event; IXML_Document *doc; HT_DBG_FUNC_START(HT_MOD_DMC, HT_BIT_MANY,EventType, "EventType = "); SEM_WAIT(); me->sdk_err = 0; me->http_err = 0; me->upnp_err = 0; if(me->ActionResult) ixmlDocument_free(me->ActionResult); me->ActionResult = NULL; if(me->subdoc) ixmlDocument_free(me->subdoc); me->subdoc = NULL; me->nb_matched = 0; me->nb_returned= 0; me->updateID = 0; if( Event==NULL || cookie==NULL ) goto cleanup; HT_DBG_FUNC(pEvt->ErrCode, "ErrCode = "); me->sdk_err = pEvt->ErrCode; me->ActionResult = pEvt->ActionResult; pEvt->ActionResult = NULL; doc = me->ActionResult; if(!doc) goto cleanup; const char* s = XMLUtil_FindFirstElementValue(XML_D2N (doc), "UpdateID", true, false); STRING_TO_INT (s, me->updateID, 0); HT_DBG_FUNC(me->updateID, "updateID = "); s = XMLUtil_FindFirstElementValue(XML_D2N (doc), "TotalMatches", true, false); STRING_TO_INT (s, me->nb_matched, 0); HT_DBG_FUNC(me->nb_matched, "TotalMatches = "); s = XMLUtil_FindFirstElementValue(XML_D2N (doc), "NumberReturned", true, false); STRING_TO_INT (s, me->nb_returned, 0); HT_DBG_FUNC(me->nb_returned, "NumberReturned = "); if(s) { const char* const resstr = XMLUtil_FindFirstElementValue(XML_D2N (doc), "Result", true, false); if(me->nb_returned == 0) { HT_DBG_FUNC(0, resstr); } if (resstr) { me->subdoc = ixmlParseBuffer (discard_const_p (char, resstr)); HT_DBG_FUNC((int)(me->subdoc), "me->subdoc = "); } goto cleanup; } s = XMLUtil_FindFirstElementValue(XML_D2N (doc), "faultstring", true, false); if(s && !strcmp(s, "UPnPError")) { s = XMLUtil_FindFirstElementValue(XML_D2N (doc), "errorDescription", true, false); HT_DBG_FUNC(0, s); s = XMLUtil_FindFirstElementValue(XML_D2N (doc), "errorCode", true, false); if(s) me->upnp_err = atoi(s); } cleanup: kill = me->killMeInCallback; if( me->syncBrowsing == 1 ) { me->syncBrowsing = 0; sem_post( &(me->semResultOK) ); } else { if( me->OnBrowseResult && me->parent ) me->OnBrowseResult(me->nb_returned, me->parent); } me->busy = 0; SEM_POST(); if( kill ) me->Release(me); HT_DBG_FUNC_END(kill, NULL); return kill; }