示例#1
0
/**
 * Does the same as vlc_scandir(), but takes an open directory pointer
 * instead of a directory path.
 */
int vlc_loaddir( DIR *dir, char ***namelist,
                  int (*select)( const char * ),
                  int (*compar)( const char **, const char ** ) )
{
    assert (dir);

    if (select == NULL)
        select = dummy_select;

    char **tab = NULL;
    unsigned num = 0;

    rewinddir (dir);

    for (unsigned size = 0;;)
    {
        errno = 0;
        char *entry = vlc_readdir (dir);
        if (entry == NULL)
        {
            if (errno)
                goto error;
            break;
        }

        if (!select (entry))
        {
            free (entry);
            continue;
        }

        if (num >= size)
        {
            size = size ? (2 * size) : 16;
            char **newtab = (char **)realloc (tab, sizeof (*tab) * (size));			// sunqueen modify

            if (unlikely(newtab == NULL))
            {
                free (entry);
                goto error;
            }
            tab = newtab;
        }

        tab[num++] = entry;
    }

    if (compar != NULL)
        qsort (tab, num, sizeof (*tab),
               (int (*)( const void *, const void *))compar);
    *namelist = tab;
    return num;

error:
    for (unsigned i = 0; i < num; i++)
        free (tab[i]);
    free (tab);
    return -1;
}
示例#2
0
文件: filesystem.c 项目: mstorsjo/vlc
/**
 * Does the same as vlc_scandir(), but takes an open directory pointer
 * instead of a directory path.
 */
int vlc_loaddir( DIR *dir, char ***namelist,
                  int (*select)( const char * ),
                  int (*compar)( const char **, const char ** ) )
{
    assert (dir);

    if (select == NULL)
        select = dummy_select;

    char **tab = NULL;
    unsigned num = 0;

    rewinddir (dir);

    for (unsigned size = 0;;)
    {
        errno = 0;
        const char *entry = vlc_readdir (dir);
        if (entry == NULL)
        {
            if (errno)
                goto error;
            break;
        }

        if (!select (entry))
            continue;

        if (num >= size)
        {
            size = size ? (2 * size) : 16;
            char **newtab = realloc (tab, sizeof (*tab) * (size));

            if (unlikely(newtab == NULL))
                goto error;
            tab = newtab;
        }

        tab[num] = strdup(entry);
        if (likely(tab[num] != NULL))
            num++;
    }

    if (compar != NULL && num > 0)
        vlc_qsort(tab, num, sizeof (*tab), compar_void, compar);
    *namelist = tab;
    return num;

error:
    for (unsigned i = 0; i < num; i++)
        free (tab[i]);
    free (tab);
    return -1;
}
void ThemeRepository::parseDirectory( const string &rDir_locale )
{
    DIR *pDir;
    char *pszDirContent;
    // Path separator
    const string &sep = OSFactory::instance( getIntf() )->getDirSeparator();

    // Open the dir
    // FIXME: parseDirectory should be invoked with UTF-8 input instead!!
    string rDir = sFromLocale( rDir_locale );
    pDir = vlc_opendir( rDir.c_str() );

    if( pDir == NULL )
    {
        // An error occurred
        msg_Dbg( getIntf(), "cannot open directory %s", rDir.c_str() );
        return;
    }

    // While we still have entries in the directory
    while( ( pszDirContent = vlc_readdir( pDir ) ) != NULL )
    {
        string name = pszDirContent;
        string extension;
        if( name.size() > 4 )
        {
            extension = name.substr( name.size() - 4, 4 );
        }
        if( extension == ".vlt" || extension == ".wsz" )
        {
            string path = rDir + sep + name;
            string shortname = name.substr( 0, name.size() - 4 );
            for( string::size_type i = 0; i < shortname.size(); i++ )
                shortname[i] = ( i == 0 ) ?
                               toupper( shortname[i] ) :
                               tolower( shortname[i] );
            m_skinsMap[shortname] = path;

            msg_Dbg( getIntf(), "found skin %s", path.c_str() );
        }

        free( pszDirContent );
    }

    closedir( pDir );
}
示例#4
0
int playlist_FindArtInCache( input_item_t *p_item )
{
    char *psz_path = ArtCachePath( p_item );

    if( !psz_path )
        return VLC_EGENERIC;

    /* Check if file exists */
    DIR *p_dir = vlc_opendir( psz_path );
    if( !p_dir )
    {
        free( psz_path );
        return VLC_EGENERIC;
    }

    bool b_found = false;
    char *psz_filename;
    while( !b_found && (psz_filename = vlc_readdir( p_dir )) )
    {
        if( !strncmp( psz_filename, "art", 3 ) )
        {
            char *psz_file;
            if( asprintf( &psz_file, "%s" DIR_SEP "%s",
                          psz_path, psz_filename ) != -1 )
            {
                char *psz_uri = make_URI( psz_file, "file" );
                if( psz_uri )
                {
                    input_item_SetArtURL( p_item, psz_uri );
                    free( psz_uri );
                }
                free( psz_file );
            }

            b_found = true;
        }
        free( psz_filename );
    }

    /* */
    closedir( p_dir );
    free( psz_path );
    return b_found ? VLC_SUCCESS : VLC_EGENERIC;
}
示例#5
0
文件: net.c 项目: 5UN5H1N3/vlc
static int vlclua_opendir( lua_State *L )
{
    const char *psz_dir = luaL_checkstring( L, 1 );
    DIR *p_dir;
    int i = 0;

    if( ( p_dir = vlc_opendir( psz_dir ) ) == NULL )
        return luaL_error( L, "cannot open directory `%s'.", psz_dir );

    lua_newtable( L );
    for( ;; )
    {
        const char *psz_filename = vlc_readdir( p_dir );
        if( !psz_filename ) break;
        i++;
        lua_pushstring( L, psz_filename );
        lua_rawseti( L, -2, i );
    }
    closedir( p_dir );
    return 1;
}
示例#6
0
文件: theme_loader.cpp 项目: paa/vlc
bool ThemeLoader::findFile( const string &rootDir, const string &rFileName,
                            string &themeFilePath )
{
    // Path separator
    const string &sep = OSFactory::instance( getIntf() )->getDirSeparator();

    DIR *pCurrDir;
    char *pszDirContent;

    // Open the dir
    pCurrDir = vlc_opendir( rootDir.c_str() );

    if( pCurrDir == NULL )
    {
        // An error occurred
        msg_Dbg( getIntf(), "cannot open directory %s", rootDir.c_str() );
        return false;
    }

    // While we still have entries in the directory
    while( ( pszDirContent = vlc_readdir( pCurrDir ) ) != NULL )
    {
        string newURI = rootDir + sep + pszDirContent;

        // Skip . and ..
        if( string( pszDirContent ) != "." &&
            string( pszDirContent ) != ".." )
        {
#if defined( S_ISDIR )
            struct stat stat_data;

            if( ( vlc_stat( newURI.c_str(), &stat_data ) == 0 )
             && S_ISDIR(stat_data.st_mode) )
#elif defined( DT_DIR )
            if( pDirContent->d_type & DT_DIR )
#else
            if( 0 )
#endif
            {
                // Can we find the file in this subdirectory?
                if( findFile( newURI, rFileName, themeFilePath ) )
                {
                    free( pszDirContent );
                    closedir( pCurrDir );
                    return true;
                }
            }
            else
            {
                // Found the theme file?
                if( rFileName == string( pszDirContent ) )
                {
                    themeFilePath = newURI;
                    free( pszDirContent );
                    closedir( pCurrDir );
                    return true;
                }
            }
        }

        free( pszDirContent );
    }

    closedir( pCurrDir );
    return false;
}
示例#7
0
文件: directory.c 项目: IAPark/vlc
int DirRead (stream_t *access, input_item_node_t *node)
{
    access_sys_t *sys = access->p_sys;
    const char *entry;
    int ret = VLC_SUCCESS;

    bool special_files = var_InheritBool(access, "list-special-files");

    struct vlc_readdir_helper rdh;
    vlc_readdir_helper_init(&rdh, access, node);

    while (ret == VLC_SUCCESS && (entry = vlc_readdir(sys->dir)) != NULL)
    {
        struct stat st;
        int type;

#ifdef HAVE_OPENAT
        if (fstatat(dirfd(sys->dir), entry, &st, 0))
            continue;
#else
        char path[PATH_MAX];

        if (snprintf(path, PATH_MAX, "%s"DIR_SEP"%s", access->psz_filepath,
                     entry) >= PATH_MAX || vlc_stat(path, &st))
            continue;
#endif
        switch (st.st_mode & S_IFMT)
        {
            case S_IFBLK:
                if (!special_files)
                    continue;
                type = ITEM_TYPE_DISC;
                break;
            case S_IFCHR:
                if (!special_files)
                    continue;
                type = ITEM_TYPE_CARD;
                break;
            case S_IFIFO:
                if (!special_files)
                    continue;
                type = ITEM_TYPE_STREAM;
                break;
            case S_IFREG:
                type = ITEM_TYPE_FILE;
                break;
            case S_IFDIR:
                type = ITEM_TYPE_DIRECTORY;
                break;
            /* S_IFLNK cannot occur while following symbolic links */
            /* S_IFSOCK cannot be opened with open()/openat() */
            default:
                continue; /* ignore */
        }

        /* Create an input item for the current entry */
        char *encoded = vlc_uri_encode(entry);
        if (unlikely(encoded == NULL))
        {
            ret = VLC_ENOMEM;
            break;
        }

        char *uri;
        if (unlikely(asprintf(&uri, "%s/%s", sys->base_uri, encoded) == -1))
            uri = NULL;
        free(encoded);
        if (unlikely(uri == NULL))
        {
            ret = VLC_ENOMEM;
            break;
        }
        ret = vlc_readdir_helper_additem(&rdh, uri, NULL, entry, type,
                                         ITEM_NET_UNKNOWN);
        free(uri);
    }

    vlc_readdir_helper_finish(&rdh, ret == VLC_SUCCESS);

    return ret;
}
示例#8
0
文件: bank.c 项目: etix/vlc
/**
 * Recursively browses a directory to look for plug-ins.
 */
static void AllocatePluginDir (module_bank_t *bank, unsigned maxdepth,
                               const char *absdir, const char *reldir)
{
    if (maxdepth == 0)
        return;
    maxdepth--;

    DIR *dh = vlc_opendir (absdir);
    if (dh == NULL)
        return;

    /* Parse the directory and try to load all files it contains. */
    for (;;)
    {
        char *relpath = NULL, *abspath = NULL;
        const char *file = vlc_readdir (dh);
        if (file == NULL)
            break;

        /* Skip ".", ".." */
        if (!strcmp (file, ".") || !strcmp (file, ".."))
            continue;

        /* Compute path relative to plug-in base directory */
        if (reldir != NULL)
        {
            if (asprintf (&relpath, "%s"DIR_SEP"%s", reldir, file) == -1)
                relpath = NULL;
        }
        else
            relpath = strdup (file);
        if (unlikely(relpath == NULL))
            continue;

        /* Compute absolute path */
        if (asprintf (&abspath, "%s"DIR_SEP"%s", bank->base, relpath) == -1)
        {
            abspath = NULL;
            goto skip;
        }

        struct stat st;
        if (vlc_stat (abspath, &st) == -1)
            goto skip;

        if (S_ISREG (st.st_mode))
        {
            static const char prefix[] = "lib";
            static const char suffix[] = "_plugin"LIBEXT;
            size_t len = strlen (file);

#ifndef __OS2__
            /* Check that file matches the "lib*_plugin"LIBEXT pattern */
            if (len > strlen (suffix)
             && !strncmp (file, prefix, strlen (prefix))
             && !strcmp (file + len - strlen (suffix), suffix))
#else
            /* We load all the files ending with LIBEXT on OS/2,
             * because OS/2 has a 8.3 length limitation for DLL name */
            if (len > strlen (LIBEXT)
             && !strcasecmp (file + len - strlen (LIBEXT), LIBEXT))
#endif
                AllocatePluginFile (bank, abspath, relpath, &st);
        }
        else if (S_ISDIR (st.st_mode))
            /* Recurse into another directory */
            AllocatePluginDir (bank, maxdepth, abspath, relpath);
    skip:
        free (relpath);
        free (abspath);
    }
    closedir (dh);
}
示例#9
0
block_t *DirBlock (access_t *p_access)
{
    access_sys_t *p_sys = p_access->p_sys;
    directory_t *current = p_sys->current;

    if (p_access->info.b_eof)
        return NULL;

    if (current == NULL)
    {   /* Startup: send the XSPF header */
        static const char header[] =
            "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
            "<playlist version=\"1\" xmlns=\"http://xspf.org/ns/0/\" xmlns:vlc=\"http://www.videolan.org/vlc/playlist/ns/0/\">\n"
            " <trackList>\n";
        block_t *block = block_Alloc (sizeof (header) - 1);
        if (!block)
            goto fatal;
        memcpy (block->p_buffer, header, sizeof (header) - 1);

        /* "Open" the base directory */
        current = malloc (sizeof (*current));
        if (current == NULL)
        {
            block_Release (block);
            goto fatal;
        }
        current->parent = NULL;
        current->handle = p_sys->handle;
#ifndef HAVE_OPENAT
        current->path = strdup (p_access->psz_filepath);
#endif
        current->uri = p_sys->uri;
        if (fstat (dirfd (current->handle), &current->st))
        {
            free (current);
            block_Release (block);
            goto fatal;
        }

        p_sys->handle = NULL;
        p_sys->uri = NULL;
        p_sys->current = current;
        return block;
    }

    char *entry = vlc_readdir (current->handle);
    if (entry == NULL)
    {   /* End of directory, go back to parent */
        closedir (current->handle);
        p_sys->current = current->parent;
        free (current->uri);
#ifndef HAVE_OPENAT
        free (current->path);
#endif
        free (current);

        if (p_sys->current == NULL)
        {   /* End of XSPF playlist */
            char *footer;
            int len = asprintf( &footer, " </trackList>\n" \
                " <extension application=\"http://www.videolan.org/vlc/playlist/0\">\n" \
                "%s" \
                " </extension>\n" \
                "</playlist>\n", p_sys->psz_xspf_extension );
            if (unlikely(len == -1))
                goto fatal;

            block_t *block = block_heap_Alloc (footer, footer, len);
            if (unlikely(block == NULL))
                free (footer);
            p_access->info.b_eof = true;
            return block;
        }
        else
        {
            /* This was the end of a "subnode" */
            /* Write the ID to the extension */
            char *old_xspf_extension = p_sys->psz_xspf_extension;
            if (old_xspf_extension == NULL)
                goto fatal;

            int len2 = asprintf( &p_sys->psz_xspf_extension, "%s  </vlc:node>\n", old_xspf_extension );
            if (len2 == -1)
                goto fatal;
            free( old_xspf_extension );
        }
        return NULL;
    }

    /* Skip current, parent and hidden directories */
    if (entry[0] == '.')
    {
        free (entry);
        return NULL;
    }
    /* Handle recursion */
    if (p_sys->mode != MODE_COLLAPSE)
    {
        directory_t *sub = malloc (sizeof (*sub));
        if (sub == NULL)
        {
            free (entry);
            return NULL;
        }

        DIR *handle;
#ifdef HAVE_OPENAT
        int fd = vlc_openat (dirfd (current->handle), entry, O_RDONLY);
        if (fd != -1)
        {
            handle = fdopendir (fd);
            if (handle == NULL)
                close (fd);
        }
        else
            handle = NULL;
#else
        if (asprintf (&sub->path, "%s/%s", current->path, entry) != -1)
            handle = vlc_opendir (sub->path);
        else
            handle = NULL;
#endif
        if (handle != NULL)
        {
            sub->parent = current;
            sub->handle = handle;

            char *encoded = encode_URI_component (entry);
            if ((encoded == NULL)
             || (asprintf (&sub->uri, "%s/%s", current->uri, encoded) == -1))
                 sub->uri = NULL;
            free (encoded);

            if ((p_sys->mode == MODE_NONE)
             || fstat (dirfd (handle), &sub->st)
             || has_inode_loop (sub)
             || (sub->uri == NULL))
            {
                free (entry);
                closedir (handle);
                free (sub->uri);
                free (sub);
                return NULL;
            }
            p_sys->current = sub;

            /* Add node to xspf extension */
            char *old_xspf_extension = p_sys->psz_xspf_extension;
            if (old_xspf_extension == NULL)
            {
                free (entry);
                goto fatal;
            }

            char *title = convert_xml_special_chars (entry);
            free (entry);
            if (title == NULL
             || asprintf (&p_sys->psz_xspf_extension, "%s"
                          "  <vlc:node title=\"%s\">\n", old_xspf_extension,
                          title) == -1)
            {
                free (title);
                goto fatal;
            }
            free (title);
            free (old_xspf_extension);
            return NULL;
        }
        else
            free (sub);
    }

    /* Skip files with ignored extensions */
    if (p_sys->ignored_exts != NULL)
    {
        const char *ext = strrchr (entry, '.');
        if (ext != NULL)
        {
            size_t extlen = strlen (++ext);
            for (const char *type = p_sys->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))
                {
                    free (entry);
                    return NULL;
                }

                if (*end == '\0')
                    break;
            }
        }
    }

    char *encoded = encode_URI_component (entry);
    free (entry);
    if (encoded == NULL)
        goto fatal;
    int len = asprintf (&entry,
                        "  <track><location>%s/%s</location>\n" \
                        "   <extension application=\"http://www.videolan.org/vlc/playlist/0\">\n" \
                        "    <vlc:id>%d</vlc:id>\n" \
                        "   </extension>\n" \
                        "  </track>\n",
                        current->uri, encoded, p_sys->i_item_count++);
    free (encoded);
    if (len == -1)
        goto fatal;

    /* Write the ID to the extension */
    char *old_xspf_extension = p_sys->psz_xspf_extension;
    if (old_xspf_extension == NULL)
        goto fatal;

    int len2 = asprintf( &p_sys->psz_xspf_extension, "%s   <vlc:item tid=\"%i\" />\n",
                            old_xspf_extension, p_sys->i_item_count-1 );
    if (len2 == -1)
        goto fatal;
    free( old_xspf_extension );

    block_t *block = block_heap_Alloc (entry, entry, len);
    if (unlikely(block == NULL))
    {
        free (entry);
        goto fatal;
    }
    return block;

fatal:
    p_access->info.b_eof = true;
    return NULL;
}
示例#10
0
/*****************************************************************************
 * Open: initializes matroska demux structures
 *****************************************************************************/
static int Open( vlc_object_t * p_this )
{
    demux_t            *p_demux = (demux_t*)p_this;
    demux_sys_t        *p_sys;
    matroska_stream_c  *p_stream;
    matroska_segment_c *p_segment;
    const uint8_t      *p_peek;
    std::string         s_path, s_filename;
    vlc_stream_io_callback *p_io_callback;
    EbmlStream         *p_io_stream;
    bool                b_need_preload = false;

    /* peek the begining */
    if( vlc_stream_Peek( p_demux->s, &p_peek, 4 ) < 4 ) return VLC_EGENERIC;

    /* is a valid file */
    if( p_peek[0] != 0x1a || p_peek[1] != 0x45 ||
        p_peek[2] != 0xdf || p_peek[3] != 0xa3 ) return VLC_EGENERIC;

    /* Set the demux function */
    p_demux->pf_demux   = Demux;
    p_demux->pf_control = Control;
    p_demux->p_sys      = p_sys = new demux_sys_t( *p_demux );

    p_io_callback = new vlc_stream_io_callback( p_demux->s, false );
    p_io_stream = new (std::nothrow) EbmlStream( *p_io_callback );

    if( p_io_stream == NULL )
    {
        msg_Err( p_demux, "failed to create EbmlStream" );
        delete p_io_callback;
        delete p_sys;
        return VLC_EGENERIC;
    }

    p_stream = p_sys->AnalyseAllSegmentsFound( p_demux, p_io_stream, true );
    if( p_stream == NULL )
    {
        msg_Err( p_demux, "cannot find KaxSegment or missing mandatory KaxInfo" );
        goto error;
    }
    p_sys->streams.push_back( p_stream );

    p_stream->p_io_callback = p_io_callback;
    p_stream->p_estream = p_io_stream;

    for (size_t i=0; i<p_stream->segments.size(); i++)
    {
        p_stream->segments[i]->Preload();
        b_need_preload |= p_stream->segments[i]->b_ref_external_segments;
        if ( p_stream->segments[i]->translations.size() &&
             p_stream->segments[i]->translations[0]->codec_id == MATROSKA_CHAPTER_CODEC_DVD &&
             p_stream->segments[i]->families.size() )
            b_need_preload = true;
    }

    p_segment = p_stream->segments[0];
    if( p_segment->cluster == NULL && p_segment->stored_editions.size() == 0 )
    {
        msg_Err( p_demux, "cannot find any cluster or chapter, damaged file ?" );
        goto error;
    }

    if (b_need_preload && var_InheritBool( p_demux, "mkv-preload-local-dir" ))
    {
        msg_Dbg( p_demux, "Preloading local dir" );
        /* get the files from the same dir from the same family (based on p_demux->psz_path) */
        if ( p_demux->psz_file && !strcmp( p_demux->psz_access, "file" ) )
        {
            // assume it's a regular file
            // get the directory path
            s_path = p_demux->psz_file;
            if (s_path.at(s_path.length() - 1) == DIR_SEP_CHAR)
            {
                s_path = s_path.substr(0,s_path.length()-1);
            }
            else
            {
                if (s_path.find_last_of(DIR_SEP_CHAR) > 0)
                {
                    s_path = s_path.substr(0,s_path.find_last_of(DIR_SEP_CHAR));
                }
            }

            DIR *p_src_dir = vlc_opendir(s_path.c_str());

            if (p_src_dir != NULL)
            {
                const char *psz_file;
                while ((psz_file = vlc_readdir(p_src_dir)) != NULL)
                {
                    if (strlen(psz_file) > 4)
                    {
                        s_filename = s_path + DIR_SEP_CHAR + psz_file;

#if defined(_WIN32) || defined(__OS2__)
                        if (!strcasecmp(s_filename.c_str(), p_demux->psz_file))
#else
                        if (!s_filename.compare(p_demux->psz_file))
#endif
                        {
                            continue; // don't reuse the original opened file
                        }

                        if (!s_filename.compare(s_filename.length() - 3, 3, "mkv") ||
                            !s_filename.compare(s_filename.length() - 3, 3, "mka"))
                        {
                            // test whether this file belongs to our family
                            const uint8_t *p_peek;
                            bool          file_ok = false;
                            char          *psz_url = vlc_path2uri( s_filename.c_str(), "file" );
                            stream_t      *p_file_stream = vlc_stream_NewURL(
                                                            p_demux,
                                                            psz_url );
                            /* peek the begining */
                            if( p_file_stream &&
                                vlc_stream_Peek( p_file_stream, &p_peek, 4 ) >= 4
                                && p_peek[0] == 0x1a && p_peek[1] == 0x45 &&
                                p_peek[2] == 0xdf && p_peek[3] == 0xa3 ) file_ok = true;

                            if ( file_ok )
                            {
                                vlc_stream_io_callback *p_file_io = new vlc_stream_io_callback( p_file_stream, true );
                                EbmlStream *p_estream = new EbmlStream(*p_file_io);

                                p_stream = p_sys->AnalyseAllSegmentsFound( p_demux, p_estream );

                                if ( p_stream == NULL )
                                {
                                    msg_Dbg( p_demux, "the file '%s' will not be used", s_filename.c_str() );
                                    delete p_estream;
                                    delete p_file_io;
                                }
                                else
                                {
                                    p_stream->p_io_callback = p_file_io;
                                    p_stream->p_estream = p_estream;
                                    p_sys->streams.push_back( p_stream );
                                }
                            }
                            else
                            {
                                if( p_file_stream ) {
                                    vlc_stream_Delete( p_file_stream );
                                }
                                msg_Dbg( p_demux, "the file '%s' cannot be opened", s_filename.c_str() );
                            }
                            free( psz_url );
                        }
                    }
                }
                closedir( p_src_dir );
            }
        }

        p_sys->PreloadFamily( *p_segment );
    }
    else if (b_need_preload)
        msg_Warn( p_demux, "This file references other files, you may want to enable the preload of local directory");

    if ( !p_sys->PreloadLinked() ||
         !p_sys->PreparePlayback( *p_sys->p_current_vsegment, 0 ) )
    {
        msg_Err( p_demux, "cannot use the segment" );
        goto error;
    }

    p_sys->FreeUnused();

    p_sys->InitUi();

    return VLC_SUCCESS;

error:
    delete p_sys;
    return VLC_EGENERIC;
}
示例#11
0
文件: subtitles.c 项目: BossKing/vlc
/**
 * Detect subtitle files.
 *
 * When called this function will split up the psz_name string into a
 * directory, filename and extension. It then opens the directory
 * in which the file resides and tries to find possible matches of
 * subtitles files.
 *
 * \ingroup Demux
 * \param p_this the calling \ref input_thread_t
 * \param psz_path a list of subdirectories (separated by a ',') to look in.
 * \param psz_name_org the complete filename to base the search on.
 * \param pp_slaves an initialized input item slave list to append detected subtitles to
 * \param p_slaves pointer to the size of the slave list
 * \return VLC_SUCCESS if ok
 */
int subtitles_Detect( input_thread_t *p_this, char *psz_path, const char *psz_name_org,
                      input_item_slave_t ***ppp_slaves, int *p_slaves )
{
    int i_fuzzy = var_GetInteger( p_this, "sub-autodetect-fuzzy" );
    if ( i_fuzzy == 0 )
        return VLC_EGENERIC;
    int j, i_fname_len;
    input_item_slave_t **pp_slaves = *ppp_slaves;
    int i_slaves = *p_slaves;
    char *f_fname_noext = NULL, *f_fname_trim = NULL;
    char **subdirs; /* list of subdirectories to look in */

    if( !psz_name_org )
        return VLC_EGENERIC;

    char *psz_fname = vlc_uri2path( psz_name_org );
    if( !psz_fname )
        return VLC_EGENERIC;

    /* extract filename & dirname from psz_fname */
    char *f_dir = strdup( psz_fname );
    if( f_dir == 0 )
    {
        free( psz_fname );
        return VLC_ENOMEM;
    }

    const char *f_fname = strrchr( psz_fname, DIR_SEP_CHAR );
    if( !f_fname )
    {
        free( f_dir );
        free( psz_fname );
        return VLC_EGENERIC;
    }
    f_fname++; /* Skip the '/' */
    f_dir[f_fname - psz_fname] = 0; /* keep dir separator in f_dir */

    i_fname_len = strlen( f_fname );

    f_fname_noext = malloc(i_fname_len + 1);
    f_fname_trim = malloc(i_fname_len + 1 );
    if( !f_fname_noext || !f_fname_trim )
    {
        free( f_dir );
        free( f_fname_noext );
        free( f_fname_trim );
        free( psz_fname );
        return VLC_ENOMEM;
    }

    strcpy_strip_ext( f_fname_noext, f_fname );
    strcpy_trim( f_fname_trim, f_fname_noext );

    subdirs = paths_to_list( f_dir, psz_path );
    for( j = -1; (j == -1) || ( j >= 0 && subdirs != NULL && subdirs[j] != NULL ); j++ )
    {
        const char *psz_dir = (j < 0) ? f_dir : subdirs[j];
        if( psz_dir == NULL || ( j >= 0 && !strcmp( psz_dir, f_dir ) ) )
            continue;

        /* parse psz_src dir */
        DIR *dir = vlc_opendir( psz_dir );
        if( dir == NULL )
            continue;

        msg_Dbg( p_this, "looking for a subtitle file in %s", psz_dir );

        const char *psz_name;
        while( (psz_name = vlc_readdir( dir )) )
        {
            if( psz_name[0] == '.' || !subtitles_Filter( psz_name ) )
                continue;

            char tmp_fname_noext[strlen( psz_name ) + 1];
            char tmp_fname_trim[strlen( psz_name ) + 1];
            char tmp_fname_ext[strlen( psz_name ) + 1];
            const char *tmp;
            int i_prio = 0;

            /* retrieve various parts of the filename */
            strcpy_strip_ext( tmp_fname_noext, psz_name );
            strcpy_get_ext( tmp_fname_ext, psz_name );
            strcpy_trim( tmp_fname_trim, tmp_fname_noext );

            if( !strcmp( tmp_fname_trim, f_fname_trim ) )
            {
                /* matches the movie name exactly */
                i_prio = SLAVE_PRIORITY_MATCH_ALL;
            }
            else if( (tmp = strstr( tmp_fname_trim, f_fname_trim )) )
            {
                /* contains the movie name */
                tmp += strlen( f_fname_trim );
                if( whiteonly( tmp ) )
                {
                    /* chars in front of the movie name */
                    i_prio = SLAVE_PRIORITY_MATCH_RIGHT;
                }
                else
                {
                    /* chars after (and possibly in front of)
                     * the movie name */
                    i_prio = SLAVE_PRIORITY_MATCH_LEFT;
                }
            }
            else if( j == -1 )
            {
                /* doesn't contain the movie name, prefer files in f_dir over subdirs */
                i_prio = SLAVE_PRIORITY_MATCH_NONE;
            }
            if( i_prio >= i_fuzzy )
            {
                struct stat st;
                char *path;

                size_t i_len = strlen( psz_dir );
                const char *psz_format;
                if ( i_len == 0 )
                    continue;
                if( psz_dir[i_len - 1] == DIR_SEP_CHAR )
                    psz_format = "%s%s";
                else
                    psz_format = "%s"DIR_SEP"%s";

                if( asprintf( &path, psz_format, psz_dir, psz_name ) < 0 )
                    continue;

                if( strcmp( path, psz_fname )
                 && vlc_stat( path, &st ) == 0
                 && S_ISREG( st.st_mode ) )
                {
                    msg_Dbg( p_this,
                            "autodetected subtitle: %s with priority %d",
                            path, i_prio );
                    char *psz_uri = vlc_path2uri( path, NULL );
                    input_item_slave_t *p_sub = psz_uri != NULL ?
                        input_item_slave_New( psz_uri, SLAVE_TYPE_SPU, i_prio )
                        : NULL;
                    if( p_sub )
                    {
                        p_sub->b_forced = true;
                        INSERT_ELEM( pp_slaves, i_slaves, i_slaves, p_sub );
                    }
                    free( psz_uri );
                }
                free( path );
            }
        }
        closedir( dir );
    }
    if( subdirs )
    {
        for( j = 0; subdirs[j]; j++ )
            free( subdirs[j] );
        free( subdirs );
    }
    free( f_dir );
    free( f_fname_trim );
    free( f_fname_noext );
    free( psz_fname );

    for( int i = 0; i < i_slaves; i++ )
    {
        input_item_slave_t *p_sub = pp_slaves[i];

        bool b_reject = false;
        char *psz_ext = strrchr( p_sub->psz_uri, '.' );
        if( !psz_ext )
            continue;
        psz_ext++;

        if( !strcasecmp( psz_ext, "sub" ) )
        {
            for( int j = 0; j < i_slaves; j++ )
            {
                input_item_slave_t *p_sub_inner = pp_slaves[j];

                /* A slave can be null if it's already rejected */
                if( p_sub_inner == NULL )
                    continue;

                /* check that the filenames without extension match */
                if( strncasecmp( p_sub->psz_uri, p_sub_inner->psz_uri,
                    strlen( p_sub->psz_uri ) - 3 ) )
                    continue;

                char *psz_ext_inner = strrchr( p_sub_inner->psz_uri, '.' );
                if( !psz_ext_inner )
                    continue;
                psz_ext_inner++;

                /* check that we have an idx file */
                if( !strcasecmp( psz_ext_inner, "idx" ) )
                {
                    b_reject = true;
                    break;
                }
            }
        }
        else if( !strcasecmp( psz_ext, "cdg" ) )
        {
            if( p_sub->i_priority < SLAVE_PRIORITY_MATCH_ALL )
                b_reject = true;
        }
        if( b_reject )
        {
            pp_slaves[i] = NULL;
            input_item_slave_Delete( p_sub );
        }
    }

    /* Sort alphabetically */
    if( i_slaves > 0 )
        qsort( pp_slaves, i_slaves, sizeof (input_item_slave_t*), slave_strcmp );

    *ppp_slaves = pp_slaves; /* in case of realloc */
    *p_slaves = i_slaves;
    return VLC_SUCCESS;
}