[vlc-commits] input: move access_fsdir to input/item.c

Thomas Guillem git at videolan.org
Wed Sep 20 16:57:06 CEST 2017


vlc | branch: master | Thomas Guillem <thomas at gllm.fr> | Wed Sep 20 09:21:41 2017 +0200| [c458178af2c4f9afb73612e62dc077989ee26e91] | committer: Thomas Guillem

input: move access_fsdir to input/item.c

> http://git.videolan.org/gitweb.cgi/vlc.git/?a=commit;h=c458178af2c4f9afb73612e62dc077989ee26e91
---

 include/vlc_access.h     |  45 ------
 include/vlc_input_item.h |  45 ++++++
 src/input/access.c       | 362 -----------------------------------------------
 src/input/item.c         | 362 +++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 407 insertions(+), 407 deletions(-)

diff --git a/include/vlc_access.h b/include/vlc_access.h
index 1f168c19a8..da06554814 100644
--- a/include/vlc_access.h
+++ b/include/vlc_access.h
@@ -75,51 +75,6 @@ VLC_API int access_vaDirectoryControlHelper( stream_t *p_access, int i_query, va
     } while(0)
 
 /**
- * Access pf_readdir helper struct
- * \see access_fsdir_init()
- * \see access_fsdir_additem()
- * \see access_fsdir_finish()
- */
-struct access_fsdir
-{
-    input_item_node_t *p_node;
-    void **pp_slaves;
-    unsigned int i_slaves;
-    int i_sub_autodetect_fuzzy;
-    bool b_show_hiddenfiles;
-    char *psz_ignored_exts;
-};
-
-/**
- * Init a access_fsdir struct
- *
- * \param p_fsdir need to be cleaned with access_fsdir_finish()
- * \param p_node node that will be used to add items
- */
-VLC_API void access_fsdir_init(struct access_fsdir *p_fsdir,
-                               stream_t *p_access, input_item_node_t *p_node);
-
-/**
- * Finish adding items to the node
- *
- * \param b_success if true, items of the node will be sorted.
- */
-VLC_API void access_fsdir_finish(struct access_fsdir *p_fsdir, bool b_success);
-
-/**
- * Add a new input_item_t entry to the node of the access_fsdir struct.
- *
- * \param p_fsdir previously inited access_fsdir struct
- * \param psz_uri uri of the new item
- * \param psz_filename file name of the new item
- * \param i_type see \ref input_item_type_e
- * \param i_net see \ref input_item_net_type
- */
-VLC_API int access_fsdir_additem(struct access_fsdir *p_fsdir,
-                                 const char *psz_uri, const char *psz_filename,
-                                 int i_type, int i_net);
-
-/**
  * @} @}
  */
 
diff --git a/include/vlc_input_item.h b/include/vlc_input_item.h
index 5656dc6c2c..b5932607e8 100644
--- a/include/vlc_input_item.h
+++ b/include/vlc_input_item.h
@@ -410,4 +410,49 @@ struct input_stats_t
     int64_t i_lost_abuffers;
 };
 
+/**
+ * Access pf_readdir helper struct
+ * \see access_fsdir_init()
+ * \see access_fsdir_additem()
+ * \see access_fsdir_finish()
+ */
+struct access_fsdir
+{
+    input_item_node_t *p_node;
+    void **pp_slaves;
+    unsigned int i_slaves;
+    int i_sub_autodetect_fuzzy;
+    bool b_show_hiddenfiles;
+    char *psz_ignored_exts;
+};
+
+/**
+ * Init a access_fsdir struct
+ *
+ * \param p_fsdir need to be cleaned with access_fsdir_finish()
+ * \param p_node node that will be used to add items
+ */
+VLC_API void access_fsdir_init(struct access_fsdir *p_fsdir,
+                               stream_t *p_access, input_item_node_t *p_node);
+
+/**
+ * Finish adding items to the node
+ *
+ * \param b_success if true, items of the node will be sorted.
+ */
+VLC_API void access_fsdir_finish(struct access_fsdir *p_fsdir, bool b_success);
+
+/**
+ * Add a new input_item_t entry to the node of the access_fsdir struct.
+ *
+ * \param p_fsdir previously inited access_fsdir struct
+ * \param psz_uri uri of the new item
+ * \param psz_filename file name of the new item
+ * \param i_type see \ref input_item_type_e
+ * \param i_net see \ref input_item_net_type
+ */
+VLC_API int access_fsdir_additem(struct access_fsdir *p_fsdir,
+                                 const char *psz_uri, const char *psz_filename,
+                                 int i_type, int i_net);
+
 #endif
diff --git a/src/input/access.c b/src/input/access.c
index 6852ade7d9..2e7c1aea1d 100644
--- a/src/input/access.c
+++ b/src/input/access.c
@@ -28,13 +28,11 @@
 #include <assert.h>
 #include <stdlib.h>
 #include <string.h>
-#include <ctype.h>
 
 #include <vlc_common.h>
 #include <vlc_url.h>
 #include <vlc_modules.h>
 #include <vlc_interrupt.h>
-#include <vlc_strings.h>
 
 #include <libvlc.h>
 #include "stream.h"
@@ -319,363 +317,3 @@ stream_t *stream_AccessNew(vlc_object_t *parent, input_thread_t *input,
         s = stream_FilterChainNew(s, cachename);
     return stream_FilterAutoNew(s);
 }
-
-static int compar_type(input_item_t *p1, input_item_t *p2)
-{
-    if (p1->i_type != p2->i_type)
-    {
-        if (p1->i_type == ITEM_TYPE_DIRECTORY)
-            return -1;
-        if (p2->i_type == ITEM_TYPE_DIRECTORY)
-            return 1;
-    }
-    return 0;
-}
-
-static int compar_filename(const void *a, const void *b)
-{
-    input_item_node_t *const *na = a, *const *nb = b;
-    input_item_t *ia = (*na)->p_item, *ib = (*nb)->p_item;
-
-    int i_ret = compar_type(ia, ib);
-    if (i_ret != 0)
-        return i_ret;
-
-    return vlc_filenamecmp(ia->psz_name, ib->psz_name);
-}
-
-static void fsdir_sort(input_item_node_t *p_node)
-{
-    if (p_node->i_children <= 0)
-        return;
-
-    /* Lock first all children. This avoids to lock/unlock them from each
-     * compar callback call */
-    for (int i = 0; i < p_node->i_children; i++)
-        vlc_mutex_lock(&p_node->pp_children[i]->p_item->lock);
-
-    /* Sort current node */
-    qsort(p_node->pp_children, p_node->i_children,
-          sizeof(input_item_node_t *), compar_filename);
-
-    /* Unlock all children */
-    for (int i = 0; i < p_node->i_children; i++)
-        vlc_mutex_unlock(&p_node->pp_children[i]->p_item->lock);
-
-    /* Sort all children */
-    for (int i = 0; i < p_node->i_children; i++)
-        fsdir_sort(p_node->pp_children[i]);
-}
-
-/**
- * Does the provided file name has one of the extension provided ?
- */
-static bool fsdir_has_ext(const char *psz_filename,
-                          const char *psz_ignored_exts)
-{
-    if (psz_ignored_exts == NULL)
-        return false;
-
-    const char *ext = strrchr(psz_filename, '.');
-    if (ext == NULL)
-        return false;
-
-    size_t extlen = strlen(++ext);
-
-    for (const char *type = psz_ignored_exts, *end; type[0]; type = end + 1)
-    {
-        end = strchr(type, ',');
-        if (end == NULL)
-            end = type + strlen(type);
-
-        if (type + extlen == end && !strncasecmp(ext, type, extlen))
-            return true;
-
-        if (*end == '\0')
-            break;
-    }
-
-    return false;
-}
-
-static bool fsdir_is_ignored(struct access_fsdir *p_fsdir,
-                             const char *psz_filename)
-{
-    return (psz_filename[0] == '\0'
-         || strcmp(psz_filename, ".") == 0
-         || strcmp(psz_filename, "..") == 0
-         || (!p_fsdir->b_show_hiddenfiles && psz_filename[0] == '.')
-         || fsdir_has_ext(psz_filename, p_fsdir->psz_ignored_exts));
-}
-
-struct fsdir_slave
-{
-    input_item_slave_t *p_slave;
-    char *psz_filename;
-    input_item_node_t *p_node;
-};
-
-static char *fsdir_name_from_filename(const char *psz_filename)
-{
-    /* remove leading white spaces */
-    while (*psz_filename != '\0' && *psz_filename == ' ')
-        psz_filename++;
-
-    char *psz_name = strdup(psz_filename);
-    if (!psz_name)
-        return NULL;
-
-    /* remove extension */
-    char *psz_ptr = strrchr(psz_name, '.');
-    if (psz_ptr && psz_ptr != psz_name)
-        *psz_ptr = '\0';
-
-    /* remove trailing white spaces */
-    int i = strlen(psz_name) - 1;
-    while (psz_name[i] == ' ' && i >= 0)
-        psz_name[i--] = '\0';
-
-    /* convert to lower case */
-    psz_ptr = psz_name;
-    while (*psz_ptr != '\0')
-    {
-        *psz_ptr = tolower(*psz_ptr);
-        psz_ptr++;
-    }
-
-    return psz_name;
-}
-
-static uint8_t fsdir_get_slave_priority(input_item_t *p_item,
-                                        input_item_slave_t *p_slave,
-                                        const char *psz_slave_filename)
-{
-    uint8_t i_priority = SLAVE_PRIORITY_MATCH_NONE;
-    char *psz_item_name = fsdir_name_from_filename(p_item->psz_name);
-    char *psz_slave_name = fsdir_name_from_filename(psz_slave_filename);
-
-    if (!psz_item_name || !psz_slave_name)
-        goto done;
-
-    /* check if the names match exactly */
-    if (!strcmp(psz_item_name, psz_slave_name))
-    {
-        i_priority = SLAVE_PRIORITY_MATCH_ALL;
-        goto done;
-    }
-
-    /* "cdg" slaves have to be a full match */
-    if (p_slave->i_type == SLAVE_TYPE_SPU)
-    {
-        char *psz_ext = strrchr(psz_slave_name, '.');
-        if (psz_ext != NULL && strcasecmp(++psz_ext, "cdg") == 0)
-            goto done;
-    }
-
-    /* check if the item name is a substring of the slave name */
-    const char *psz_sub = strstr(psz_slave_name, psz_item_name);
-
-    if (psz_sub)
-    {
-        /* check if the item name was found at the end of the slave name */
-        if (strlen(psz_sub + strlen(psz_item_name)) == 0)
-        {
-            i_priority = SLAVE_PRIORITY_MATCH_RIGHT;
-            goto done;
-        }
-        else
-        {
-            i_priority = SLAVE_PRIORITY_MATCH_LEFT;
-            goto done;
-        }
-    }
-
-done:
-    free(psz_item_name);
-    free(psz_slave_name);
-    return i_priority;
-}
-
-static int fsdir_should_match_idx(struct access_fsdir *p_fsdir,
-                                  struct fsdir_slave *p_fsdir_sub)
-{
-    char *psz_ext = strrchr(p_fsdir_sub->psz_filename, '.');
-    if (!psz_ext)
-        return false;
-    psz_ext++;
-
-    if (strcasecmp(psz_ext, "sub") != 0)
-        return false;
-
-    for (unsigned int i = 0; i < p_fsdir->i_slaves; i++)
-    {
-        struct fsdir_slave *p_fsdir_slave = p_fsdir->pp_slaves[i];
-
-        if (p_fsdir_slave == NULL || p_fsdir_slave == p_fsdir_sub)
-            continue;
-
-        /* check that priorities match */
-        if (p_fsdir_slave->p_slave->i_priority !=
-            p_fsdir_sub->p_slave->i_priority)
-            continue;
-
-        /* check that the filenames without extension match */
-        if (strncasecmp(p_fsdir_sub->psz_filename, p_fsdir_slave->psz_filename,
-                        strlen(p_fsdir_sub->psz_filename) - 3 ) != 0)
-            continue;
-
-        /* check that we have an idx file */
-        char *psz_ext_idx = strrchr(p_fsdir_slave->psz_filename, '.');
-        if (psz_ext_idx == NULL)
-            continue;
-        psz_ext_idx++;
-        if (strcasecmp(psz_ext_idx, "idx" ) == 0)
-            return true;
-    }
-    return false;
-}
-
-static void fsdir_attach_slaves(struct access_fsdir *p_fsdir)
-{
-    if (p_fsdir->i_sub_autodetect_fuzzy == 0)
-        return;
-
-    /* Try to match slaves for each items of the node */
-    for (int i = 0; i < p_fsdir->p_node->i_children; i++)
-    {
-        input_item_node_t *p_node = p_fsdir->p_node->pp_children[i];
-        input_item_t *p_item = p_node->p_item;
-
-        for (unsigned int j = 0; j < p_fsdir->i_slaves; j++)
-        {
-            struct fsdir_slave *p_fsdir_slave = p_fsdir->pp_slaves[j];
-
-            /* Don't try to match slaves with themselves or slaves already
-             * attached with the higher priority */
-            if (p_fsdir_slave->p_node == p_node
-             || p_fsdir_slave->p_slave->i_priority == SLAVE_PRIORITY_MATCH_ALL)
-                continue;
-
-            uint8_t i_priority =
-                fsdir_get_slave_priority(p_item, p_fsdir_slave->p_slave,
-                                         p_fsdir_slave->psz_filename);
-
-            if (i_priority < p_fsdir->i_sub_autodetect_fuzzy)
-                continue;
-
-            /* Drop the ".sub" slave if a ".idx" slave matches */
-            if (p_fsdir_slave->p_slave->i_type == SLAVE_TYPE_SPU
-             && fsdir_should_match_idx(p_fsdir, p_fsdir_slave))
-                continue;
-
-            input_item_slave_t *p_slave =
-                input_item_slave_New(p_fsdir_slave->p_slave->psz_uri,
-                                     p_fsdir_slave->p_slave->i_type,
-                                     i_priority);
-            if (p_slave == NULL)
-                break;
-
-            if (input_item_AddSlave(p_item, p_slave) != VLC_SUCCESS)
-            {
-                input_item_slave_Delete(p_slave);
-                break;
-            }
-
-            /* Remove the corresponding node if any: This slave won't be
-             * added in the parent node */
-            if (p_fsdir_slave->p_node != NULL)
-            {
-                input_item_node_RemoveNode(p_fsdir->p_node,
-                                           p_fsdir_slave->p_node);
-                input_item_node_Delete(p_fsdir_slave->p_node);
-                p_fsdir_slave->p_node = NULL;
-            }
-
-            p_fsdir_slave->p_slave->i_priority = i_priority;
-        }
-    }
-}
-
-void access_fsdir_init(struct access_fsdir *p_fsdir,
-                       stream_t *p_access, input_item_node_t *p_node)
-{
-    p_fsdir->p_node = p_node;
-    p_fsdir->b_show_hiddenfiles = var_InheritBool(p_access, "show-hiddenfiles");
-    p_fsdir->psz_ignored_exts = var_InheritString(p_access, "ignore-filetypes");
-    bool b_autodetect = var_InheritBool(p_access, "sub-autodetect-file");
-    p_fsdir->i_sub_autodetect_fuzzy = !b_autodetect ? 0 :
-        var_InheritInteger(p_access, "sub-autodetect-fuzzy");
-    TAB_INIT(p_fsdir->i_slaves, p_fsdir->pp_slaves);
-}
-
-void access_fsdir_finish(struct access_fsdir *p_fsdir, bool b_success)
-{
-    if (b_success)
-    {
-        fsdir_attach_slaves(p_fsdir);
-        fsdir_sort(p_fsdir->p_node);
-    }
-    free(p_fsdir->psz_ignored_exts);
-
-    /* Remove unmatched slaves */
-    for (unsigned int i = 0; i < p_fsdir->i_slaves; i++)
-    {
-        struct fsdir_slave *p_fsdir_slave = p_fsdir->pp_slaves[i];
-        if (p_fsdir_slave != NULL)
-        {
-            input_item_slave_Delete(p_fsdir_slave->p_slave);
-            free(p_fsdir_slave->psz_filename);
-            free(p_fsdir_slave);
-        }
-    }
-    TAB_CLEAN(p_fsdir->i_slaves, p_fsdir->pp_slaves);
-}
-
-int access_fsdir_additem(struct access_fsdir *p_fsdir,
-                         const char *psz_uri, const char *psz_filename,
-                         int i_type, int i_net)
-{
-    enum slave_type i_slave_type;
-    struct fsdir_slave *p_fsdir_slave = NULL;
-    input_item_node_t *p_node;
-
-    if (p_fsdir->i_sub_autodetect_fuzzy != 0
-     && input_item_slave_GetType(psz_filename, &i_slave_type))
-    {
-        p_fsdir_slave = malloc(sizeof(*p_fsdir_slave));
-        if (!p_fsdir_slave)
-            return VLC_ENOMEM;
-
-        p_fsdir_slave->p_node = NULL;
-        p_fsdir_slave->psz_filename = strdup(psz_filename);
-        p_fsdir_slave->p_slave = input_item_slave_New(psz_uri, i_slave_type,
-                                                      SLAVE_PRIORITY_MATCH_NONE);
-        if (!p_fsdir_slave->p_slave || !p_fsdir_slave->psz_filename)
-        {
-            free(p_fsdir_slave->psz_filename);
-            free(p_fsdir_slave);
-            return VLC_ENOMEM;
-        }
-
-        TAB_APPEND(p_fsdir->i_slaves, p_fsdir->pp_slaves, p_fsdir_slave);
-    }
-
-    if (fsdir_is_ignored(p_fsdir, psz_filename))
-        return VLC_SUCCESS;
-
-    input_item_t *p_item = input_item_NewExt(psz_uri, psz_filename, -1,
-                                             i_type, i_net);
-    if (p_item == NULL)
-        return VLC_ENOMEM;
-
-    input_item_CopyOptions(p_item, p_fsdir->p_node->p_item);
-    p_node = input_item_node_AppendItem(p_fsdir->p_node, p_item);
-    input_item_Release(p_item);
-
-    /* A slave can also be an item. If there is a match, this item will be
-     * removed from the parent node. This is not a common case, since most
-     * slaves will be ignored by fsdir_is_ignored() */
-    if (p_fsdir_slave != NULL)
-        p_fsdir_slave->p_node = p_node;
-    return VLC_SUCCESS;
-}
diff --git a/src/input/item.c b/src/input/item.c
index a8deb19b70..56faff5c19 100644
--- a/src/input/item.c
+++ b/src/input/item.c
@@ -27,11 +27,13 @@
 #include <assert.h>
 #include <time.h>
 #include <limits.h>
+#include <ctype.h>
 
 #include <vlc_common.h>
 #include <vlc_url.h>
 #include <vlc_interface.h>
 #include <vlc_charset.h>
+#include <vlc_strings.h>
 
 #include "item.h"
 #include "info.h"
@@ -1319,3 +1321,363 @@ void input_item_UpdateTracksInfo(input_item_t *item, const es_format_t *fmt)
     TAB_APPEND(item->i_es, item->es, fmt_copy);
     vlc_mutex_unlock( &item->lock );
 }
+
+static int compar_type(input_item_t *p1, input_item_t *p2)
+{
+    if (p1->i_type != p2->i_type)
+    {
+        if (p1->i_type == ITEM_TYPE_DIRECTORY)
+            return -1;
+        if (p2->i_type == ITEM_TYPE_DIRECTORY)
+            return 1;
+    }
+    return 0;
+}
+
+static int compar_filename(const void *a, const void *b)
+{
+    input_item_node_t *const *na = a, *const *nb = b;
+    input_item_t *ia = (*na)->p_item, *ib = (*nb)->p_item;
+
+    int i_ret = compar_type(ia, ib);
+    if (i_ret != 0)
+        return i_ret;
+
+    return vlc_filenamecmp(ia->psz_name, ib->psz_name);
+}
+
+static void fsdir_sort(input_item_node_t *p_node)
+{
+    if (p_node->i_children <= 0)
+        return;
+
+    /* Lock first all children. This avoids to lock/unlock them from each
+     * compar callback call */
+    for (int i = 0; i < p_node->i_children; i++)
+        vlc_mutex_lock(&p_node->pp_children[i]->p_item->lock);
+
+    /* Sort current node */
+    qsort(p_node->pp_children, p_node->i_children,
+          sizeof(input_item_node_t *), compar_filename);
+
+    /* Unlock all children */
+    for (int i = 0; i < p_node->i_children; i++)
+        vlc_mutex_unlock(&p_node->pp_children[i]->p_item->lock);
+
+    /* Sort all children */
+    for (int i = 0; i < p_node->i_children; i++)
+        fsdir_sort(p_node->pp_children[i]);
+}
+
+/**
+ * Does the provided file name has one of the extension provided ?
+ */
+static bool fsdir_has_ext(const char *psz_filename,
+                          const char *psz_ignored_exts)
+{
+    if (psz_ignored_exts == NULL)
+        return false;
+
+    const char *ext = strrchr(psz_filename, '.');
+    if (ext == NULL)
+        return false;
+
+    size_t extlen = strlen(++ext);
+
+    for (const char *type = psz_ignored_exts, *end; type[0]; type = end + 1)
+    {
+        end = strchr(type, ',');
+        if (end == NULL)
+            end = type + strlen(type);
+
+        if (type + extlen == end && !strncasecmp(ext, type, extlen))
+            return true;
+
+        if (*end == '\0')
+            break;
+    }
+
+    return false;
+}
+
+static bool fsdir_is_ignored(struct access_fsdir *p_fsdir,
+                             const char *psz_filename)
+{
+    return (psz_filename[0] == '\0'
+         || strcmp(psz_filename, ".") == 0
+         || strcmp(psz_filename, "..") == 0
+         || (!p_fsdir->b_show_hiddenfiles && psz_filename[0] == '.')
+         || fsdir_has_ext(psz_filename, p_fsdir->psz_ignored_exts));
+}
+
+struct fsdir_slave
+{
+    input_item_slave_t *p_slave;
+    char *psz_filename;
+    input_item_node_t *p_node;
+};
+
+static char *fsdir_name_from_filename(const char *psz_filename)
+{
+    /* remove leading white spaces */
+    while (*psz_filename != '\0' && *psz_filename == ' ')
+        psz_filename++;
+
+    char *psz_name = strdup(psz_filename);
+    if (!psz_name)
+        return NULL;
+
+    /* remove extension */
+    char *psz_ptr = strrchr(psz_name, '.');
+    if (psz_ptr && psz_ptr != psz_name)
+        *psz_ptr = '\0';
+
+    /* remove trailing white spaces */
+    int i = strlen(psz_name) - 1;
+    while (psz_name[i] == ' ' && i >= 0)
+        psz_name[i--] = '\0';
+
+    /* convert to lower case */
+    psz_ptr = psz_name;
+    while (*psz_ptr != '\0')
+    {
+        *psz_ptr = tolower(*psz_ptr);
+        psz_ptr++;
+    }
+
+    return psz_name;
+}
+
+static uint8_t fsdir_get_slave_priority(input_item_t *p_item,
+                                        input_item_slave_t *p_slave,
+                                        const char *psz_slave_filename)
+{
+    uint8_t i_priority = SLAVE_PRIORITY_MATCH_NONE;
+    char *psz_item_name = fsdir_name_from_filename(p_item->psz_name);
+    char *psz_slave_name = fsdir_name_from_filename(psz_slave_filename);
+
+    if (!psz_item_name || !psz_slave_name)
+        goto done;
+
+    /* check if the names match exactly */
+    if (!strcmp(psz_item_name, psz_slave_name))
+    {
+        i_priority = SLAVE_PRIORITY_MATCH_ALL;
+        goto done;
+    }
+
+    /* "cdg" slaves have to be a full match */
+    if (p_slave->i_type == SLAVE_TYPE_SPU)
+    {
+        char *psz_ext = strrchr(psz_slave_name, '.');
+        if (psz_ext != NULL && strcasecmp(++psz_ext, "cdg") == 0)
+            goto done;
+    }
+
+    /* check if the item name is a substring of the slave name */
+    const char *psz_sub = strstr(psz_slave_name, psz_item_name);
+
+    if (psz_sub)
+    {
+        /* check if the item name was found at the end of the slave name */
+        if (strlen(psz_sub + strlen(psz_item_name)) == 0)
+        {
+            i_priority = SLAVE_PRIORITY_MATCH_RIGHT;
+            goto done;
+        }
+        else
+        {
+            i_priority = SLAVE_PRIORITY_MATCH_LEFT;
+            goto done;
+        }
+    }
+
+done:
+    free(psz_item_name);
+    free(psz_slave_name);
+    return i_priority;
+}
+
+static int fsdir_should_match_idx(struct access_fsdir *p_fsdir,
+                                  struct fsdir_slave *p_fsdir_sub)
+{
+    char *psz_ext = strrchr(p_fsdir_sub->psz_filename, '.');
+    if (!psz_ext)
+        return false;
+    psz_ext++;
+
+    if (strcasecmp(psz_ext, "sub") != 0)
+        return false;
+
+    for (unsigned int i = 0; i < p_fsdir->i_slaves; i++)
+    {
+        struct fsdir_slave *p_fsdir_slave = p_fsdir->pp_slaves[i];
+
+        if (p_fsdir_slave == NULL || p_fsdir_slave == p_fsdir_sub)
+            continue;
+
+        /* check that priorities match */
+        if (p_fsdir_slave->p_slave->i_priority !=
+            p_fsdir_sub->p_slave->i_priority)
+            continue;
+
+        /* check that the filenames without extension match */
+        if (strncasecmp(p_fsdir_sub->psz_filename, p_fsdir_slave->psz_filename,
+                        strlen(p_fsdir_sub->psz_filename) - 3 ) != 0)
+            continue;
+
+        /* check that we have an idx file */
+        char *psz_ext_idx = strrchr(p_fsdir_slave->psz_filename, '.');
+        if (psz_ext_idx == NULL)
+            continue;
+        psz_ext_idx++;
+        if (strcasecmp(psz_ext_idx, "idx" ) == 0)
+            return true;
+    }
+    return false;
+}
+
+static void fsdir_attach_slaves(struct access_fsdir *p_fsdir)
+{
+    if (p_fsdir->i_sub_autodetect_fuzzy == 0)
+        return;
+
+    /* Try to match slaves for each items of the node */
+    for (int i = 0; i < p_fsdir->p_node->i_children; i++)
+    {
+        input_item_node_t *p_node = p_fsdir->p_node->pp_children[i];
+        input_item_t *p_item = p_node->p_item;
+
+        for (unsigned int j = 0; j < p_fsdir->i_slaves; j++)
+        {
+            struct fsdir_slave *p_fsdir_slave = p_fsdir->pp_slaves[j];
+
+            /* Don't try to match slaves with themselves or slaves already
+             * attached with the higher priority */
+            if (p_fsdir_slave->p_node == p_node
+             || p_fsdir_slave->p_slave->i_priority == SLAVE_PRIORITY_MATCH_ALL)
+                continue;
+
+            uint8_t i_priority =
+                fsdir_get_slave_priority(p_item, p_fsdir_slave->p_slave,
+                                         p_fsdir_slave->psz_filename);
+
+            if (i_priority < p_fsdir->i_sub_autodetect_fuzzy)
+                continue;
+
+            /* Drop the ".sub" slave if a ".idx" slave matches */
+            if (p_fsdir_slave->p_slave->i_type == SLAVE_TYPE_SPU
+             && fsdir_should_match_idx(p_fsdir, p_fsdir_slave))
+                continue;
+
+            input_item_slave_t *p_slave =
+                input_item_slave_New(p_fsdir_slave->p_slave->psz_uri,
+                                     p_fsdir_slave->p_slave->i_type,
+                                     i_priority);
+            if (p_slave == NULL)
+                break;
+
+            if (input_item_AddSlave(p_item, p_slave) != VLC_SUCCESS)
+            {
+                input_item_slave_Delete(p_slave);
+                break;
+            }
+
+            /* Remove the corresponding node if any: This slave won't be
+             * added in the parent node */
+            if (p_fsdir_slave->p_node != NULL)
+            {
+                input_item_node_RemoveNode(p_fsdir->p_node,
+                                           p_fsdir_slave->p_node);
+                input_item_node_Delete(p_fsdir_slave->p_node);
+                p_fsdir_slave->p_node = NULL;
+            }
+
+            p_fsdir_slave->p_slave->i_priority = i_priority;
+        }
+    }
+}
+
+void access_fsdir_init(struct access_fsdir *p_fsdir,
+                       stream_t *p_access, input_item_node_t *p_node)
+{
+    p_fsdir->p_node = p_node;
+    p_fsdir->b_show_hiddenfiles = var_InheritBool(p_access, "show-hiddenfiles");
+    p_fsdir->psz_ignored_exts = var_InheritString(p_access, "ignore-filetypes");
+    bool b_autodetect = var_InheritBool(p_access, "sub-autodetect-file");
+    p_fsdir->i_sub_autodetect_fuzzy = !b_autodetect ? 0 :
+        var_InheritInteger(p_access, "sub-autodetect-fuzzy");
+    TAB_INIT(p_fsdir->i_slaves, p_fsdir->pp_slaves);
+}
+
+void access_fsdir_finish(struct access_fsdir *p_fsdir, bool b_success)
+{
+    if (b_success)
+    {
+        fsdir_attach_slaves(p_fsdir);
+        fsdir_sort(p_fsdir->p_node);
+    }
+    free(p_fsdir->psz_ignored_exts);
+
+    /* Remove unmatched slaves */
+    for (unsigned int i = 0; i < p_fsdir->i_slaves; i++)
+    {
+        struct fsdir_slave *p_fsdir_slave = p_fsdir->pp_slaves[i];
+        if (p_fsdir_slave != NULL)
+        {
+            input_item_slave_Delete(p_fsdir_slave->p_slave);
+            free(p_fsdir_slave->psz_filename);
+            free(p_fsdir_slave);
+        }
+    }
+    TAB_CLEAN(p_fsdir->i_slaves, p_fsdir->pp_slaves);
+}
+
+int access_fsdir_additem(struct access_fsdir *p_fsdir,
+                         const char *psz_uri, const char *psz_filename,
+                         int i_type, int i_net)
+{
+    enum slave_type i_slave_type;
+    struct fsdir_slave *p_fsdir_slave = NULL;
+    input_item_node_t *p_node;
+
+    if (p_fsdir->i_sub_autodetect_fuzzy != 0
+     && input_item_slave_GetType(psz_filename, &i_slave_type))
+    {
+        p_fsdir_slave = malloc(sizeof(*p_fsdir_slave));
+        if (!p_fsdir_slave)
+            return VLC_ENOMEM;
+
+        p_fsdir_slave->p_node = NULL;
+        p_fsdir_slave->psz_filename = strdup(psz_filename);
+        p_fsdir_slave->p_slave = input_item_slave_New(psz_uri, i_slave_type,
+                                                      SLAVE_PRIORITY_MATCH_NONE);
+        if (!p_fsdir_slave->p_slave || !p_fsdir_slave->psz_filename)
+        {
+            free(p_fsdir_slave->psz_filename);
+            free(p_fsdir_slave);
+            return VLC_ENOMEM;
+        }
+
+        TAB_APPEND(p_fsdir->i_slaves, p_fsdir->pp_slaves, p_fsdir_slave);
+    }
+
+    if (fsdir_is_ignored(p_fsdir, psz_filename))
+        return VLC_SUCCESS;
+
+    input_item_t *p_item = input_item_NewExt(psz_uri, psz_filename, -1,
+                                             i_type, i_net);
+    if (p_item == NULL)
+        return VLC_ENOMEM;
+
+    input_item_CopyOptions(p_item, p_fsdir->p_node->p_item);
+    p_node = input_item_node_AppendItem(p_fsdir->p_node, p_item);
+    input_item_Release(p_item);
+
+    /* A slave can also be an item. If there is a match, this item will be
+     * removed from the parent node. This is not a common case, since most
+     * slaves will be ignored by fsdir_is_ignored() */
+    if (p_fsdir_slave != NULL)
+        p_fsdir_slave->p_node = p_node;
+    return VLC_SUCCESS;
+}



More information about the vlc-commits mailing list