From 4d9d36139eed70da5ee922501bcf68443a349b44 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Micha=C5=82=20Piechowiak?= <misiek.piechowiak@gmail.com>
Date: Fri, 2 Aug 2013 18:55:34 +0200
Subject: [PATCH 05/11] platinum: add SearchSync method to SyncMediaBrowser

---
 .../Devices/MediaServer/PltSyncMediaBrowser.cpp    | 150 +++++++++++++++++++--
 .../Devices/MediaServer/PltSyncMediaBrowser.h      |  25 +++-
 2 files changed, 164 insertions(+), 11 deletions(-)

diff --git a/lib/libUPnP/Platinum/Source/Devices/MediaServer/PltSyncMediaBrowser.cpp b/lib/libUPnP/Platinum/Source/Devices/MediaServer/PltSyncMediaBrowser.cpp
index 24219ff..96e4121 100644
--- a/lib/libUPnP/Platinum/Source/Devices/MediaServer/PltSyncMediaBrowser.cpp
+++ b/lib/libUPnP/Platinum/Source/Devices/MediaServer/PltSyncMediaBrowser.cpp
@@ -126,6 +126,24 @@ PLT_SyncMediaBrowser::Find(const char* ip, PLT_DeviceDataReference& device)
     return NPT_FAILURE;
 }
 
+static void OnResult(NPT_Result               res, 
+                     PLT_DeviceDataReference& device, 
+                     PLT_BrowseInfo*          info, 
+                     void*                    userdata)
+{
+  NPT_COMPILER_UNUSED(device);
+
+  if (!userdata) return;
+
+  PLT_BrowseDataReference* data = (PLT_BrowseDataReference*) userdata;
+  (*data)->res = res;
+  if (NPT_SUCCEEDED(res) && info) {
+      (*data)->info = *info;
+  }
+  (*data)->shared_var.SetValue(1);
+  delete data;
+}
+
 /*----------------------------------------------------------------------
 |   PLT_SyncMediaBrowser::OnBrowseResult
 +---------------------------------------------------------------------*/
@@ -135,17 +153,19 @@ PLT_SyncMediaBrowser::OnBrowseResult(NPT_Result               res,
                                      PLT_BrowseInfo*          info, 
                                      void*                    userdata)
 {
-    NPT_COMPILER_UNUSED(device);
-
-    if (!userdata) return;
+  OnResult(res, device, info, userdata);
+}
 
-    PLT_BrowseDataReference* data = (PLT_BrowseDataReference*) userdata;
-    (*data)->res = res;
-    if (NPT_SUCCEEDED(res) && info) {
-        (*data)->info = *info;
-    }
-    (*data)->shared_var.SetValue(1);
-    delete data;
+/*----------------------------------------------------------------------
+|   PLT_SyncMediaBrowser::OnSearchResult
++---------------------------------------------------------------------*/
+void
+PLT_SyncMediaBrowser::OnSearchResult(NPT_Result               res, 
+                                     PLT_DeviceDataReference& device, 
+                                     PLT_BrowseInfo*          info, 
+                                     void*                    userdata)
+{
+  OnResult(res, device, info, userdata);
 }
 
 /*----------------------------------------------------------------------
@@ -228,6 +248,38 @@ PLT_SyncMediaBrowser::BrowseSync(PLT_BrowseDataReference& browse_data,
 }
 
 /*----------------------------------------------------------------------
+|   PLT_SyncMediaBrowser::SearchSync
++---------------------------------------------------------------------*/
+NPT_Result 
+PLT_SyncMediaBrowser::SearchSync(PLT_BrowseDataReference& browse_data,
+                                 PLT_DeviceDataReference& device, 
+                                 const char*              container_id,
+                                 const char*              search_criteria,
+                                 NPT_Int32                index, 
+                                 NPT_Int32                count,
+                                 const char*              filter)
+{
+    NPT_Result res;
+
+    browse_data->shared_var.SetValue(0);
+    browse_data->info.si = index;
+
+    // send off the search packet.  Note that this will
+    // not block.  There is a call to WaitForResponse in order
+    // to block until the response comes back.
+    res = PLT_MediaBrowser::Search(device,
+        container_id,
+        search_criteria,
+        index,
+        count,
+        filter,
+        new PLT_BrowseDataReference(browse_data));
+    NPT_CHECK_SEVERE(res);
+
+    return WaitForResponse(browse_data->shared_var);
+}
+
+/*----------------------------------------------------------------------
 |   PLT_SyncMediaBrowser::BrowseSync
 +---------------------------------------------------------------------*/
 NPT_Result
@@ -319,6 +371,84 @@ done:
 }
 
 /*----------------------------------------------------------------------
+|   PLT_SyncMediaBrowser::SearchSync
++---------------------------------------------------------------------*/
+NPT_Result
+PLT_SyncMediaBrowser::SearchSync(PLT_DeviceDataReference&      device,
+                                 const char*                   container_id,
+                                 const char*                   search_criteria,
+                                 PLT_MediaObjectListReference& list,
+                                 NPT_Int32                     start, /* = 0 */
+                                 NPT_Cardinal                  max_results /* = 0 */)
+{
+    NPT_Result res = NPT_FAILURE;
+    NPT_Int32  index = start;
+    NPT_UInt32 count = 0;
+
+    // reset output params
+    list = NULL;
+
+    do {	
+        PLT_BrowseDataReference browse_data(new PLT_BrowseData(), true);
+
+        // send off the search packet.  Note that this will
+        // not block.  There is a call to WaitForResponse in order
+        // to block until the response comes back.
+        res = SearchSync(
+            browse_data,
+            device,
+            container_id,
+            search_criteria,
+            index,
+            200); // DLNA recommendations for browsing children is no more than 30 at a time
+
+        NPT_CHECK_LABEL_WARNING(res, done);
+        
+        if (NPT_FAILED(browse_data->res)) {
+            res = browse_data->res;
+            NPT_CHECK_LABEL_WARNING(res, done);
+        }
+
+        // server returned no more, bail now
+        if (browse_data->info.nr == 0)
+            break;
+
+        if (browse_data->info.nr != browse_data->info.items->GetItemCount()) {
+            NPT_LOG_WARNING_2("Server returned unexpected number of items (%d vs %d)",
+                              browse_data->info.nr, browse_data->info.items->GetItemCount());
+        }
+        count += std::max<NPT_UInt32>(browse_data->info.nr, browse_data->info.items->GetItemCount());
+
+        if (list.IsNull()) {
+            list = browse_data->info.items;
+        } else {
+            list->Add(*browse_data->info.items);
+            // clear the list items so that the data inside is not
+            // cleaned up by PLT_MediaItemList dtor since we copied
+            // each pointer into the new list.
+            browse_data->info.items->Clear();
+        }
+
+        // stop now if our list contains exactly what the server said it had.
+        // Note that the server could return 0 if it didn't know how many items were
+        // available. In this case we have to continue browsing until
+        // nothing is returned back by the server.
+        // Unless we were told to stop after reaching a certain amount to avoid
+        // length delays
+        // (some servers may return a total matches out of whack at some point too)
+        if ((browse_data->info.tm && browse_data->info.tm <= count) ||
+            (max_results && count >= max_results))
+            break;
+
+        // ask for the next chunk of entries
+        index = count;
+    } while(1);
+
+done:
+    return res;
+}
+
+/*----------------------------------------------------------------------
 |   PLT_SyncMediaBrowser::IsCached
 +---------------------------------------------------------------------*/
 bool
diff --git a/lib/libUPnP/Platinum/Source/Devices/MediaServer/PltSyncMediaBrowser.h b/lib/libUPnP/Platinum/Source/Devices/MediaServer/PltSyncMediaBrowser.h
index ffdddda..5ef9f37 100644
--- a/lib/libUPnP/Platinum/Source/Devices/MediaServer/PltSyncMediaBrowser.h
+++ b/lib/libUPnP/Platinum/Source/Devices/MediaServer/PltSyncMediaBrowser.h
@@ -61,6 +61,9 @@ typedef struct PLT_BrowseData {
 
 typedef NPT_Reference<PLT_BrowseData> PLT_BrowseDataReference;
 
+// explicitely specify res otherwise WMP won't return a URL!
+#define PLT_DEFAULT_FILTER  "dc:date,dc:description,upnp:longDescription,upnp:genre,res,res@duration,res@size,upnp:albumArtURI,upnp:rating,upnp:lastPlaybackPosition,upnp:lastPlaybackTime,upnp:playbackCount,upnp:originalTrackNumber,upnp:episodeNumber,upnp:programTitle,upnp:seriesTitle,upnp:album,upnp:artist,upnp:author,upnp:director,dc:publisher,searchable,childCount,dc:title,dc:creator,upnp:actor,res@resolution,upnp:episodeCount,upnp:episodeSeason,xbmc:dateadded,xbmc:rating,xbmc:votes,xbmc:artwork"
+
 /*----------------------------------------------------------------------
 |   PLT_MediaContainerListener
 +---------------------------------------------------------------------*/
@@ -96,6 +99,10 @@ public:
                                 PLT_DeviceDataReference& device, 
                                 PLT_BrowseInfo*          info, 
                                 void*                    userdata);
+    virtual void OnSearchResult(NPT_Result               res, 
+                                PLT_DeviceDataReference& device, 
+                                PLT_BrowseInfo*          info, 
+                                void*                    userdata);
 
     // methods
     void       SetContainerListener(PLT_MediaContainerChangesListener* listener) {
@@ -108,6 +115,13 @@ public:
                           NPT_Int32                     start = 0,
                           NPT_Cardinal                  max_results = 0); // 0 means all
 
+    NPT_Result SearchSync(PLT_DeviceDataReference&      device,
+                          const char*                   container_id,
+                          const char*                   search_criteria,
+                          PLT_MediaObjectListReference& list,
+                          NPT_Int32                     start = 0,
+                          NPT_Cardinal                  max_results = 0); // 0 means all
+
     const NPT_Lock<PLT_DeviceMap>& GetMediaServersMap() const { return m_MediaServers; }
     bool IsCached(const char* uuid, const char* object_id);
 
@@ -118,8 +132,17 @@ protected:
                           NPT_Int32                index, 
                           NPT_Int32                count,
                           bool                     browse_metadata = false,
-                          const char*              filter = "dc:date,dc:description,upnp:longDescription,upnp:genre,res,res@duration,res@size,upnp:albumArtURI,upnp:rating,upnp:lastPlaybackPosition,upnp:lastPlaybackTime,upnp:playbackCount,upnp:originalTrackNumber,upnp:episodeNumber,upnp:programTitle,upnp:seriesTitle,upnp:album,upnp:artist,upnp:author,upnp:director,dc:publisher,searchable,childCount,dc:title,dc:creator,upnp:actor,res@resolution,upnp:episodeCount,upnp:episodeSeason,xbmc:dateadded,xbmc:rating,xbmc:votes,xbmc:artwork", // explicitely specify res otherwise WMP won't return a URL!
+                          const char*              filter = PLT_DEFAULT_FILTER,
                           const char*              sort = "");
+
+    NPT_Result SearchSync(PLT_BrowseDataReference& browse_data,
+                          PLT_DeviceDataReference& device, 
+                          const char*              container_id,
+                          const char*              search_criteria,
+                          NPT_Int32                index, 
+                          NPT_Int32                count,
+                          const char*              filter = PLT_DEFAULT_FILTER); // explicitely specify res otherwise WMP won't return a URL!
+
 private:
     NPT_Result Find(const char* ip, PLT_DeviceDataReference& device);
     NPT_Result WaitForResponse(NPT_SharedVariable& shared_var);
-- 
1.7.11.msysgit.0