Example #1
0
/// Wrapper around FromLocale, to avoid the need to call LocaleFree()
static inline std::string sFromLocale( const std::string &rLocale )
{
    const char *s = FromLocale( rLocale.c_str() );
    std::string res = s;
    LocaleFree( s );
    return res;
}
Example #2
0
/**
 * Opens a system file handle relative to an existing directory handle.
 *
 * @param dir directory file descriptor
 * @param filename file path to open (with UTF-8 encoding)
 * @param flags open() flags, see the C library open() documentation
 * @return a file handle on success, -1 on error (see errno).
 * @note Contrary to standard open(), this function returns file handles
 * with the close-on-exec flag enabled.
 */
int vlc_openat (int dir, const char *filename, int flags, ...)
{
    unsigned int mode = 0;
    va_list ap;

    va_start (ap, flags);
    if (flags & O_CREAT)
        mode = va_arg (ap, unsigned int);
    va_end (ap);

#ifdef O_CLOEXEC
    flags |= O_CLOEXEC;
#endif

    const char *local_name = ToLocale (filename);
    if (local_name == NULL)
    {
        errno = ENOENT;
        return -1;
    }

#ifdef HAVE_OPENAT
    int fd = openat (dir, local_name, flags, mode);
    if (fd != -1)
        fcntl (fd, F_SETFD, FD_CLOEXEC);
#else
    int fd = -1;
    errno = ENOSYS;
#endif

    LocaleFree (local_name);
    return fd;
}
Example #3
0
/**
 * Opens a system file handle.
 *
 * @param filename file path to open (with UTF-8 encoding)
 * @param flags open() flags, see the C library open() documentation
 * @return a file handle on success, -1 on error (see errno).
 * @note Contrary to standard open(), this function returns file handles
 * with the close-on-exec flag enabled.
 */
int vlc_open (const char *filename, int flags, ...)
{
    unsigned int mode = 0;
    va_list ap;

    va_start (ap, flags);
    if (flags & O_CREAT)
        mode = va_arg (ap, unsigned int);
    va_end (ap);

    const char *local_name = ToLocale (filename);

    if (local_name == NULL)
    {
        errno = ENOENT;
        return -1;
    }

    int fd = open (local_name, flags, mode);
    if (fd != -1)
        fcntl (fd, F_SETFD, FD_CLOEXEC);

    LocaleFree (local_name);
    return fd;
}
Example #4
0
/**
 * Moves a file atomically. This only works within a single file system.
 *
 * @param oldpath path to the file before the move
 * @param newpath intended path to the file after the move
 * @return A 0 return value indicates success. A -1 return value indicates an
 *        error, and an error code is stored in errno
 */
int vlc_rename (const char *oldpath, const char *newpath)
{
    const char *lo = ToLocale (oldpath);
    if (lo == NULL)
        goto error;

    const char *ln = ToLocale (newpath);
    if (ln == NULL)
    {
        LocaleFree (lo);
error:
        errno = ENOENT;
        return -1;
    }

    int ret = rename (lo, ln);
    LocaleFree (lo);
    LocaleFree (ln);
    return ret;
}
Example #5
0
/**
 * Removes a file.
 *
 * @param filename a UTF-8 string with the name of the file you want to delete.
 * @return A 0 return value indicates success. A -1 return value indicates an
 *        error, and an error code is stored in errno
 */
int vlc_unlink (const char *filename)
{
    const char *local_name = ToLocale (filename);
    if (unlikely(local_name == NULL))
    {
        errno = ENOENT;
        return -1;
    }

    int ret = unlink (local_name);
    LocaleFree (local_name);
    return ret;
}
Example #6
0
/**
 * Opens a DIR pointer.
 *
 * @param dirname UTF-8 representation of the directory name
 * @return a pointer to the DIR struct, or NULL in case of error.
 * Release with standard closedir().
 */
DIR *vlc_opendir (const char *dirname)
{
    const char *local_name = ToLocale (dirname);
    if (unlikely(local_name == NULL))
    {
        errno = ENOENT;
        return NULL;
    }

    DIR *dir = opendir (local_name);
    LocaleFree (local_name);
    return dir;
}
Example #7
0
/**
 * Creates a directory using UTF-8 paths.
 *
 * @param dirname a UTF-8 string with the name of the directory that you
 *        want to create.
 * @param mode directory permissions
 * @return 0 on success, -1 on error (see errno).
 */
int vlc_mkdir (const char *dirname, mode_t mode)
{
    char *locname = ToLocale (dirname);
    if (unlikely(locname == NULL))
    {
        errno = ENOENT;
        return -1;
    }

    int res = mkdir (locname, mode);
    LocaleFree (locname);
    return res;
}
Example #8
0
static int vlc_statEx (const char *filename, struct stat *buf, bool deref)
{
    const char *local_name = ToLocale (filename);
    if (unlikely(local_name == NULL))
    {
        errno = ENOENT;
        return -1;
    }

    int res = deref ? stat (local_name, buf)
                    : lstat (local_name, buf);
    LocaleFree (local_name);
    return res;
}
Example #9
0
File: dirs.c Project: sivertaa/vlc
static char *config_GetAppDir (const char *xdg_name, const char *xdg_default)
{
    char *psz_dir;
    char var[sizeof ("XDG__HOME") + strlen (xdg_name)];

    /* XDG Base Directory Specification - Version 0.6 */
    snprintf (var, sizeof (var), "XDG_%s_HOME", xdg_name);

    char *psz_home = FromLocale (getenv (var));
    if( psz_home )
    {
        if( asprintf( &psz_dir, "%s/vlc", psz_home ) == -1 )
            psz_dir = NULL;
        LocaleFree (psz_home);
        return psz_dir;
    }

    psz_home = config_GetHomeDir ();
    if( psz_home == NULL
            || asprintf( &psz_dir, "%s/%s/vlc", psz_home, xdg_default ) == -1 )
        psz_dir = NULL;
    free (psz_home);
    return psz_dir;
}
Example #10
0
/*****************************************************************************
 * Open:
 *****************************************************************************/
static int Open( vlc_object_t *p_this )
{
    demux_t      *p_demux = (demux_t*)p_this;
    demux_sys_t  *p_sys;
    char         *psz_file;
    ifo_handle_t *p_vmg_file;

    if( !p_demux->psz_path || !*p_demux->psz_path )
    {
        /* Only when selected */
        if( !p_demux->psz_access || !*p_demux->psz_access )
            return VLC_EGENERIC;

        psz_file = var_InheritString( p_this, "dvd" );
    }
    else
        psz_file = strdup( p_demux->psz_path );

#ifdef WIN32
    if( psz_file != NULL )
    {
        size_t flen = strlen( psz_file );
        if( flen > 0 && psz_file[flen - 1] == '\\' )
            psz_file[flen - 1] = '\0';
    }
    else
        psz_file = strdup("");
#endif
    if( unlikely(psz_file == NULL) )
        return VLC_EGENERIC;

    /* Open dvdread */
    const char *psz_path = ToLocale( psz_file );
    dvd_reader_t *p_dvdread = DVDOpen( psz_path );

    LocaleFree( psz_path );
    if( p_dvdread == NULL )
    {
        msg_Err( p_demux, "DVDRead cannot open source: %s", psz_file );
        dialog_Fatal( p_demux, _("Playback failure"),
                      _("DVDRead could not open the disc \"%s\"."), psz_file );
        free( psz_file );
        return VLC_EGENERIC;
    }
    free( psz_file );

    /* Ifo allocation & initialisation */
    if( !( p_vmg_file = ifoOpen( p_dvdread, 0 ) ) )
    {
        msg_Warn( p_demux, "cannot open VMG info" );
        return VLC_EGENERIC;
    }
    msg_Dbg( p_demux, "VMG opened" );

    /* Fill p_demux field */
    DEMUX_INIT_COMMON(); p_sys = p_demux->p_sys;

    ps_track_init( p_sys->tk );
    p_sys->i_sar_num = 0;
    p_sys->i_sar_den = 0;
    p_sys->i_title_cur_time = (mtime_t) 0;
    p_sys->i_cell_cur_time = (mtime_t) 0;
    p_sys->i_cell_duration = (mtime_t) 0;

    p_sys->p_dvdread = p_dvdread;
    p_sys->p_vmg_file = p_vmg_file;
    p_sys->p_title = NULL;
    p_sys->p_vts_file = NULL;

    p_sys->i_title = p_sys->i_chapter = -1;
    p_sys->i_mux_rate = 0;

    p_sys->i_angle = var_CreateGetInteger( p_demux, "dvdread-angle" );
    if( p_sys->i_angle <= 0 ) p_sys->i_angle = 1;

    DemuxTitles( p_demux, &p_sys->i_angle );
    if( DvdReadSetArea( p_demux, 0, 0, p_sys->i_angle ) != VLC_SUCCESS )
    {
        Close( p_this );
        msg_Err( p_demux, "DvdReadSetArea(0,0,%i) failed (can't decrypt DVD?)",
                 p_sys->i_angle );
        return VLC_EGENERIC;
    }

    /* Update default_pts to a suitable value for dvdread access */
    var_Create( p_demux, "dvdread-caching",
                VLC_VAR_INTEGER|VLC_VAR_DOINHERIT );

    return VLC_SUCCESS;
}
Example #11
0
/*****************************************************************************
 * main: parse command line, start interface and spawn threads.
 *****************************************************************************/
int main( int i_argc, const char *ppsz_argv[] )
{
#ifdef __APPLE__
    /* The so-called POSIX-compliant MacOS X is not. 
     * SIGPIPE fires even when it is blocked in all threads! */
    signal (SIGPIPE, SIG_IGN);
#endif

#ifndef ALLOW_RUN_AS_ROOT
    if (geteuid () == 0)
    {
        fprintf (stderr, "VLC is not supposed to be run as root. Sorry.\n"
        "If you need to use real-time priorities and/or privileged TCP ports\n"
        "you can use %s-wrapper (make sure it is Set-UID root and\n"
        "cannot be run by non-trusted users first).\n", ppsz_argv[0]);
        return 1;
    }
#endif

    setlocale (LC_ALL, "");

#ifndef __APPLE__
    /* This clutters OSX GUI error logs */
    fprintf( stderr, "VLC media player %s\n", libvlc_get_version() );
#endif

#ifdef HAVE_PUTENV
#   ifndef NDEBUG
    /* Activate malloc checking routines to detect heap corruptions. */
    putenv( (char*)"MALLOC_CHECK_=2" );

    /* Disable the ugly Gnome crash dialog so that we properly segfault */
    putenv( (char *)"GNOME_DISABLE_CRASH_DIALOG=1" );
#   endif
#endif

    /* Synchronously intercepted POSIX signals.
     *
     * In a threaded program such as VLC, the only sane way to handle signals
     * is to block them in all thread but one - this is the only way to
     * predict which thread will receive them. If any piece of code depends
     * on delivery of one of this signal it is intrinsically not thread-safe
     * and MUST NOT be used in VLC, whether we like it or not.
     * There is only one exception: if the signal is raised with
     * pthread_kill() - we do not use this in LibVLC but some pthread
     * implementations use them internally. You should really use conditions
     * for thread synchronization anyway.
     *
     * Signal that request a clean shutdown, and force an unclean shutdown
     * if they are triggered again 2+ seconds later.
     * We have to handle SIGTERM cleanly because of daemon mode.
     * Note that we set the signals after the vlc_create call. */
    static const int sigs[] = {
        SIGINT, SIGHUP, SIGQUIT, SIGTERM,
    /* Signals that cause a no-op:
     * - SIGPIPE might happen with sockets and would crash VLC. It MUST be
     *   blocked by any LibVLC-dependent application, not just VLC.
     * - SIGCHLD comes after exec*() (such as httpd CGI support) and must
     *   be dequeued to cleanup zombie processes.
     */
        SIGPIPE, SIGCHLD
    };

    sigset_t set;
    sigemptyset (&set);
    for (unsigned i = 0; i < sizeof (sigs) / sizeof (sigs[0]); i++)
        sigaddset (&set, sigs[i]);

    /* Block all these signals */
    pthread_sigmask (SIG_BLOCK, &set, NULL);
    sigdelset (&set, SIGPIPE);
    sigdelset (&set, SIGCHLD);

    /* Note that FromLocale() can be used before libvlc is initialized */
    const char *argv[i_argc + 3];
    int argc = 0;

    argv[argc++] = "--no-ignore-config";
#ifdef TOP_BUILDDIR
    argv[argc++] = FromLocale ("--plugin-path="TOP_BUILDDIR"/modules");
#endif
#ifdef TOP_SRCDIR
# ifdef ENABLE_HTTPD
    argv[argc++] = FromLocale ("--http-src="TOP_SRCDIR"/share/http");
# endif
#endif

    for (int i = 1; i < i_argc; i++)
        if ((argv[argc++] = FromLocale (ppsz_argv[i])) == NULL)
            return 1; // BOOM!
    argv[argc] = NULL;

    libvlc_exception_t ex, dummy;
    libvlc_exception_init (&ex);
    libvlc_exception_init (&dummy);

    /* Initialize libvlc */
    libvlc_instance_t *vlc = libvlc_new (argc, argv, &ex);

    if (vlc != NULL)
    {
        libvlc_add_intf (vlc, "signals", &ex);
        if (libvlc_exception_raised (&ex))
        {
            libvlc_exception_clear (&ex);
            pthread_sigmask (SIG_UNBLOCK, &set, NULL);
        }
#if !defined (HAVE_MAEMO)
        libvlc_add_intf (vlc, "globalhotkeys,none", &ex);
#endif
        libvlc_exception_clear (&ex);
        libvlc_add_intf (vlc, NULL, &ex);
        libvlc_playlist_play (vlc, -1, 0, NULL, &dummy);
        libvlc_wait (vlc);

        if (libvlc_exception_raised (&ex))
            fprintf( stderr, "%s\n", libvlc_errmsg() );
        libvlc_release (vlc);
    }

    for (int i = 1; i < argc; i++)
        LocaleFree (argv[i]);

    return vlc == NULL || libvlc_exception_raised (&ex);
}
Example #12
0
File: vlc.c Project: cobr123/qtVlc
/*****************************************************************************
 * main: parse command line, start interface and spawn threads.
 *****************************************************************************/
int main( int i_argc, const char *ppsz_argv[] )
{
    /* The so-called POSIX-compliant MacOS X reportedly processes SIGPIPE even
     * if it is blocked in all thread. Also some libraries want SIGPIPE blocked
     * as they have no clue about signal masks.
     * Note: this is NOT an excuse for not protecting against SIGPIPE. If
     * LibVLC runs outside of VLC, we cannot rely on this code snippet. */
    signal (SIGPIPE, SIG_IGN);
    /* Restore default for SIGCHLD in case parent ignores it. */
    signal (SIGCHLD, SIG_DFL);

#ifdef HAVE_SETENV
# ifndef NDEBUG
    /* Activate malloc checking routines to detect heap corruptions. */
    setenv ("MALLOC_CHECK_", "2", 1);

    /* Disable the ugly Gnome crash dialog so that we properly segfault */
    setenv ("GNOME_DISABLE_CRASH_DIALOG", "1", 1);
# endif

    /* Clear the X.Org startup notification ID. Otherwise the UI might try to
     * change the environment while the process is multi-threaded. That could
     * crash. Screw you X.Org. Next time write a thread-safe specification. */
    unsetenv ("DESKTOP_STARTUP_ID");
#endif

#ifndef ALLOW_RUN_AS_ROOT
    if (geteuid () == 0)
    {
        fprintf (stderr, "VLC is not supposed to be run as root. Sorry.\n"
        "If you need to use real-time priorities and/or privileged TCP ports\n"
        "you can use %s-wrapper (make sure it is Set-UID root and\n"
        "cannot be run by non-trusted users first).\n", ppsz_argv[0]);
        return 1;
    }
#endif

    setlocale (LC_ALL, "");

#ifndef __APPLE__
    /* This clutters OSX GUI error logs */
    fprintf( stderr, "VLC media player %s (revision %s)\n",
             libvlc_get_version(), libvlc_get_changeset() );
#endif

    /* Synchronously intercepted POSIX signals.
     *
     * In a threaded program such as VLC, the only sane way to handle signals
     * is to block them in all threads but one - this is the only way to
     * predict which thread will receive them. If any piece of code depends
     * on delivery of one of this signal it is intrinsically not thread-safe
     * and MUST NOT be used in VLC, whether we like it or not.
     * There is only one exception: if the signal is raised with
     * pthread_kill() - we do not use this in LibVLC but some pthread
     * implementations use them internally. You should really use conditions
     * for thread synchronization anyway.
     *
     * Signal that request a clean shutdown, and force an unclean shutdown
     * if they are triggered again 2+ seconds later.
     * We have to handle SIGTERM cleanly because of daemon mode.
     * Note that we set the signals after the vlc_create call. */
    static const int sigs[] = {
        SIGINT, SIGHUP, SIGQUIT, SIGTERM,
    /* Signals that cause a no-op:
     * - SIGPIPE might happen with sockets and would crash VLC. It MUST be
     *   blocked by any LibVLC-dependent application, not just VLC.
     * - SIGCHLD comes after exec*() (such as httpd CGI support) and must
     *   be dequeued to cleanup zombie processes.
     */
        SIGPIPE, SIGCHLD
    };

    sigset_t set;
    sigemptyset (&set);
    for (unsigned i = 0; i < sizeof (sigs) / sizeof (sigs[0]); i++)
        sigaddset (&set, sigs[i]);
#ifdef HAVE_MAEMO
    sigaddset (&set, SIGRTMIN);
    {
        struct sigaction act = { .sa_handler = dummy_handler, };
        sigaction (SIGRTMIN, &act, NULL);
    }
#endif

    /* Block all these signals */
    pthread_sigmask (SIG_BLOCK, &set, NULL);
    sigdelset (&set, SIGPIPE);
    sigdelset (&set, SIGCHLD);

    /* Note that FromLocale() can be used before libvlc is initialized */
    const char *argv[i_argc + 3];
    int argc = 0;

    argv[argc++] = "--no-ignore-config";
#ifdef TOP_BUILDDIR
    argv[argc++] = FromLocale ("--plugin-path="TOP_BUILDDIR"/modules");
#endif
#ifdef TOP_SRCDIR
    argv[argc++] = FromLocale ("--data-path="TOP_SRCDIR"/share");
#endif

    int i = 1;
#ifdef __APPLE__
    /* When VLC.app is run by double clicking in Mac OS X, the 2nd arg
     * is the PSN - process serial number (a unique PID-ish thingie)
     * still ok for real Darwin & when run from command line
     * for example -psn_0_9306113 */
    if(i_argc >= 2 && !strncmp( ppsz_argv[1] , "-psn" , 4 ))
        i = 2;
#endif
    for (; i < i_argc; i++)
        if ((argv[argc++] = FromLocale (ppsz_argv[i])) == NULL)
            return 1; // BOOM!
    argv[argc] = NULL;

    vlc_enable_override ();

    /* Initialize libvlc */
    libvlc_instance_t *vlc = libvlc_new (argc, argv);

    if (vlc != NULL)
    {
        libvlc_set_user_agent (vlc, "VLC media player", NULL);

        if (libvlc_add_intf (vlc, "signals"))
            pthread_sigmask (SIG_UNBLOCK, &set, NULL);
#if !defined (HAVE_MAEMO) && !defined __APPLE__
        libvlc_add_intf (vlc, "globalhotkeys,none");
#endif
        if (libvlc_add_intf (vlc, NULL) == 0)
        {
            libvlc_playlist_play (vlc, -1, 0, NULL);
            libvlc_wait (vlc);
        }
        libvlc_release (vlc);
    }

    for (int i = 1; i < argc; i++)
        LocaleFree (argv[i]);

    return 0;
}
Example #13
0
File: os.c Project: FLYKingdom/vlc
/**
 * Load a dynamically linked library using a system dependent method.
 *
 * \param p_this vlc object
 * \param psz_file library file
 * \param p_handle the module handle returned
 * \return 0 on success as well as the module handle.
 */
int module_Load( vlc_object_t *p_this, const char *psz_file,
                 module_handle_t *p_handle )
{
    module_handle_t handle;

#if defined(HAVE_DL_BEOS)
    handle = load_add_on( psz_file );
    if( handle < 0 )
    {
        msg_Warn( p_this, "cannot load module `%s'", psz_file );
        return -1;
    }

#elif defined(HAVE_DL_WINDOWS)
    wchar_t psz_wfile[MAX_PATH];
    MultiByteToWideChar( CP_UTF8, 0, psz_file, -1, psz_wfile, MAX_PATH );

#ifndef UNDER_CE
    /* FIXME: this is not thread-safe -- Courmisch */
    UINT mode = SetErrorMode (SEM_FAILCRITICALERRORS);
    SetErrorMode (mode|SEM_FAILCRITICALERRORS);
#endif

    handle = LoadLibraryW( psz_wfile );

#ifndef UNDER_CE
    SetErrorMode (mode);
#endif

    if( handle == NULL )
    {
        char *psz_err = GetWindowsError();
        msg_Warn( p_this, "cannot load module `%s' (%s)", psz_file, psz_err );
        free( psz_err );
        return -1;
    }

#elif defined(HAVE_DL_DLOPEN)

# if defined (RTLD_NOW)
    const int flags = RTLD_NOW;
# elif defined (DL_LAZY)
    const int flags = DL_LAZY;
# else
    const int flags = 0;
# endif
    char *path = ToLocale( psz_file );

    handle = dlopen( path, flags );
    if( handle == NULL )
    {
        msg_Warn( p_this, "cannot load module `%s' (%s)", path, dlerror() );
        LocaleFree( path );
        return -1;
    }
    LocaleFree( path );

#elif defined(HAVE_DL_SHL_LOAD)
    handle = shl_load( psz_file, BIND_IMMEDIATE | BIND_NONFATAL, NULL );
    if( handle == NULL )
    {
        msg_Warn( p_this, "cannot load module `%s' (%m)", psz_file );
        return -1;
    }

#else
#   error "Something is wrong in modules.c"

#endif

    *p_handle = handle;
    return 0;
}
static int Open (vlc_object_t *p_this)
{
    decoder_t *p_dec = (decoder_t *)p_this;
    decoder_sys_t *p_sys;

    if (p_dec->fmt_in.i_codec != VLC_CODEC_MIDI)
        return VLC_EGENERIC;

    char *font_path = var_InheritString (p_this, "soundfont");
    if (font_path == NULL)
    {
        msg_Err (p_this, "sound font file required for synthesis");
        dialog_Fatal (p_this, _("MIDI synthesis not set up"),
            _("A sound font file (.SF2) is required for MIDI synthesis.\n"
              "Please install a sound font and configure it "
              "from the VLC preferences "
              "(Input / Codecs > Audio codecs > FluidSynth).\n"));
        return VLC_EGENERIC;
    }

    p_dec->pf_decode_audio = DecodeBlock;
    p_sys = p_dec->p_sys = malloc (sizeof (*p_sys));
    if (p_sys == NULL)
    {
        free (font_path);
        return VLC_ENOMEM;
    }

    p_sys->settings = new_fluid_settings ();
    p_sys->synth = new_fluid_synth (p_sys->settings);
    /* FIXME: I bet this is not thread-safe */
    const char *lpath = ToLocale (font_path);
    p_sys->soundfont = fluid_synth_sfload (p_sys->synth, font_path, 1);
    LocaleFree (lpath);
    if (p_sys->soundfont == -1)
    {
        msg_Err (p_this, "cannot load sound fonts file %s", font_path);
        Close (p_this);
        dialog_Fatal (p_this, _("MIDI synthesis not set up"),
            _("The specified sound font file (%s) is incorrect.\n"
              "Please install a valid sound font and reconfigure it "
              "from the VLC preferences (Codecs / Audio / FluidSynth).\n"),
              font_path);
        free (font_path);
        return VLC_EGENERIC;
    }
    free (font_path);

    p_dec->fmt_out.i_cat = AUDIO_ES;
    p_dec->fmt_out.audio.i_rate = 44100;
    p_dec->fmt_out.audio.i_channels = 2;
    p_dec->fmt_out.audio.i_original_channels =
    p_dec->fmt_out.audio.i_physical_channels =
        AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT;
    if (HAVE_FPU)
    {
        p_dec->fmt_out.i_codec = VLC_CODEC_FL32;
        p_dec->fmt_out.audio.i_bitspersample = 32;
        p_sys->fixed = false;
    }
    else
    {
        p_dec->fmt_out.i_codec = VLC_CODEC_S16N;
        p_dec->fmt_out.audio.i_bitspersample = 16;
        p_sys->fixed = true;
    }
    date_Init (&p_sys->end_date, p_dec->fmt_out.audio.i_rate, 1);
    date_Set (&p_sys->end_date, 0);

    return VLC_SUCCESS;
}
Example #15
0
static int Demux( demux_t *p_demux )
{
    char       *psz_line;
    char       *psz_name = NULL;
    char       *psz_artist = NULL;
    int        i_parsed_duration = 0;
    mtime_t    i_duration = -1;
    const char**ppsz_options = NULL;
    char *    (*pf_dup) (const char *) = p_demux->p_sys->pf_dup;
    int        i_options = 0;
    bool b_cleanup = false;
    input_item_t *p_input;

    input_item_t *p_current_input = GetCurrentItem(p_demux);

    psz_line = stream_ReadLine( p_demux->s );
    while( psz_line )
    {
        char *psz_parse = psz_line;

        /* Skip leading tabs and spaces */
        while( *psz_parse == ' ' || *psz_parse == '\t' ||
               *psz_parse == '\n' || *psz_parse == '\r' ) psz_parse++;

        if( *psz_parse == '#' )
        {
            /* Parse extra info */

            /* Skip leading tabs and spaces */
            while( *psz_parse == ' ' || *psz_parse == '\t' ||
                   *psz_parse == '\n' || *psz_parse == '\r' ||
                   *psz_parse == '#' ) psz_parse++;

            if( !*psz_parse ) goto error;

            if( !strncasecmp( psz_parse, "EXTINF:", sizeof("EXTINF:") -1 ) )
            {
                /* Extended info */
                psz_parse += sizeof("EXTINF:") - 1;
                parseEXTINF( psz_parse, &psz_artist, &psz_name, &i_parsed_duration );
                if( i_parsed_duration >= 0 )
                    i_duration = i_parsed_duration * INT64_C(1000000);
                if( psz_name )
                    psz_name = pf_dup( psz_name );
                if( psz_artist )
                    psz_artist = pf_dup( psz_artist );
            }
            else if( !strncasecmp( psz_parse, "EXTVLCOPT:",
                                   sizeof("EXTVLCOPT:") -1 ) )
            {
                /* VLC Option */
                char *psz_option;
                psz_parse += sizeof("EXTVLCOPT:") -1;
                if( !*psz_parse ) goto error;

                psz_option = pf_dup( psz_parse );
                if( psz_option )
                    INSERT_ELEM( ppsz_options, i_options, i_options,
                                 psz_option );
            }
        }
        else if( !strncasecmp( psz_parse, "RTSPtext", sizeof("RTSPtext") -1 ) )
        {
            ;/* special case to handle QuickTime RTSPtext redirect files */
        }
        else if( *psz_parse )
        {
            char *psz_mrl;

            psz_parse = pf_dup( psz_parse );
            if( !psz_name && psz_parse )
                /* Use filename as name for relative entries */
                psz_name = strdup( psz_parse );

            psz_mrl = ProcessMRL( psz_parse, p_demux->p_sys->psz_prefix );

            b_cleanup = true;
            if( !psz_mrl ) goto error;

            p_input = input_item_NewExt( p_demux, psz_mrl, psz_name,
                                        i_options, ppsz_options, 0, i_duration );

            LocaleFree( psz_parse );
            free( psz_mrl );

            if ( psz_artist && *psz_artist )
                input_item_SetArtist( p_input, psz_artist );
            if( psz_name ) input_item_SetTitle( p_input, psz_name );

            input_item_AddSubItem( p_current_input, p_input );
            vlc_gc_decref( p_input );
        }

 error:

        /* Fetch another line */
        free( psz_line );
        psz_line = stream_ReadLine( p_demux->s );
        if( !psz_line ) b_cleanup = true;

        if( b_cleanup )
        {
            /* Cleanup state */
            while( i_options-- ) free( (char*)ppsz_options[i_options] );
            free( ppsz_options );
            ppsz_options = NULL; i_options = 0;
            free( psz_name );
            psz_name = NULL;
            free( psz_artist );
            psz_artist = NULL;
            i_parsed_duration = 0;
            i_duration = -1;

            b_cleanup = false;
        }
    }
    vlc_gc_decref(p_current_input);
    var_Destroy( p_demux, "m3u-extvlcopt" );
    return 0; /* Needed for correct operation of go back */
}