<commit_before>/*****************************************************************************
 * tree.c : Playlist tree walking functions
 *****************************************************************************
 * Copyright (C) 1999-2007 VLC authors and VideoLAN
 * $Id$
 *
 * Authors: <NAME> <<EMAIL>>
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation; either version 2.1 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
 *****************************************************************************/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif

#include <vlc_common.h>
#include <assert.h>
#include "vlc_playlist.h"
#include "playlist_internal.h"

/************************************************************************
 * Local prototypes
 ************************************************************************/
playlist_item_t *GetNextUncle( playlist_t *p_playlist, playlist_item_t *p_item,
                               playlist_item_t *p_root );
playlist_item_t *GetPrevUncle( playlist_t *p_playlist, playlist_item_t *p_item,
                               playlist_item_t *p_root );

playlist_item_t *GetNextItem( playlist_t *p_playlist,
                              playlist_item_t *p_root,
                              playlist_item_t *p_item );
playlist_item_t *GetPrevItem( playlist_t *p_playlist,
                              playlist_item_t *p_item,
                              playlist_item_t *p_root );

/**
 * Create a playlist node
 *
 * \param p_playlist the playlist
 * \param psz_name the name of the node
 * \param p_parent the parent node to attach to or NULL if no attach
 * \param i_pos position of the node in the parent, PLAYLIST_END to append to end.
 * \param p_flags miscellaneous flags
 * \param p_input the input_item to attach to or NULL if it has to be created
 * \return the new node
 */
playlist_item_t * playlist_NodeCreate( playlist_t *p_playlist,
                                       const char *psz_name,
                                       playlist_item_t *p_parent, int i_pos,
                                       int i_flags )
{
    input_item_t *p_new_input;
    playlist_item_t *p_item;

    PL_ASSERT_LOCKED;
    if( !psz_name ) psz_name = _("Undefined");

    p_new_input = input_item_NewExt( NULL, psz_name, -1, ITEM_TYPE_NODE,
                                     ITEM_NET_UNKNOWN );
    p_item = playlist_ItemNewFromInput( p_playlist, p_new_input );
    vlc_gc_decref( p_new_input );

    if( p_item == NULL )  return NULL;
    p_item->i_children = 0;

    ARRAY_APPEND(pl_priv(p_playlist)->all_items, p_item);

    if( p_parent != NULL )
        playlist_NodeInsert( p_playlist, p_item, p_parent, i_pos );
    playlist_SendAddNotify( p_playlist, p_item,
                            !( i_flags & PLAYLIST_NO_REBUILD ));

    p_item->i_flags |= i_flags;

    return p_item;
}

/**
 * Remove all the children of a node and removes the node
 *
 * \param p_playlist the playlist
 * \param p_root the node
 */
void playlist_NodeDelete( playlist_t *p_playlist, playlist_item_t *p_root,
                          bool b_force )
{
    PL_ASSERT_LOCKED;

    /* Delete the children */
    for( int i = p_root->i_children - 1 ; i >= 0; i-- )
        playlist_NodeDelete( p_playlist, p_root->pp_children[i], b_force );

    /* Delete the node */
    if( p_root->i_flags & PLAYLIST_RO_FLAG && !b_force )
        return;

    pl_priv(p_playlist)->b_reset_currently_playing = true;

    int i;
    var_SetAddress( p_playlist, "playlist-item-deleted", p_root );
    ARRAY_BSEARCH( pl_priv(p_playlist)->all_items, ->i_id, int, p_root->i_id, i );
    if( i != -1 )
        ARRAY_REMOVE( pl_priv(p_playlist)->all_items, i );

    if( p_root->i_children == -1 ) {
        ARRAY_BSEARCH( p_playlist->items,->i_id, int, p_root->i_id, i );
        if( i != -1 )
            ARRAY_REMOVE( p_playlist->items, i );
    }

    /* Check if it is the current item */
    if( get_current_status_item( p_playlist ) == p_root )
    {
        /* Stop */
        playlist_Control( p_playlist, PLAYLIST_STOP, pl_Locked );
        msg_Info( p_playlist, "stopping playback" );
        /* This item can't be the next one to be played ! */
        set_current_status_item( p_playlist, NULL );
    }

    ARRAY_BSEARCH( p_playlist->current,->i_id, int, p_root->i_id, i );
    if( i != -1 )
        ARRAY_REMOVE( p_playlist->current, i );

    PL_DEBUG( "deleting item `%s'", p_root->p_input->psz_name );

    /* Remove the item from its parent */
    playlist_item_t *p_parent = p_root->p_parent;
    if( p_parent != NULL )
    {
        for( int i = 0; i < p_parent->i_children ; i++ )
        {
            if( p_parent->pp_children[i] == p_root )
            {
                REMOVE_ELEM( p_parent->pp_children, p_parent->i_children, i );
                assert( p_root->p_parent == p_parent );
            }
        }
    }

    playlist_ItemRelease( p_root );
}

int playlist_NodeInsert( playlist_t *p_playlist,
                         playlist_item_t *p_item,
                         playlist_item_t *p_parent,
                         int i_position )
{
    PL_ASSERT_LOCKED;<commit_msg>playlist: fix use after free in current array<commit_after>/*****************************************************************************
 * tree.c : Playlist tree walking functions
 *****************************************************************************
 * Copyright (C) 1999-2007 VLC authors and VideoLAN
 * $Id$
 *
 * Authors: <NAME> <<EMAIL>>
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation; either version 2.1 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
 *****************************************************************************/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif

#include <vlc_common.h>
#include <assert.h>
#include "vlc_playlist.h"
#include "playlist_internal.h"

/************************************************************************
 * Local prototypes
 ************************************************************************/
playlist_item_t *GetNextUncle( playlist_t *p_playlist, playlist_item_t *p_item,
                               playlist_item_t *p_root );
playlist_item_t *GetPrevUncle( playlist_t *p_playlist, playlist_item_t *p_item,
                               playlist_item_t *p_root );

playlist_item_t *GetNextItem( playlist_t *p_playlist,
                              playlist_item_t *p_root,
                              playlist_item_t *p_item );
playlist_item_t *GetPrevItem( playlist_t *p_playlist,
                              playlist_item_t *p_item,
                              playlist_item_t *p_root );

/**
 * Create a playlist node
 *
 * \param p_playlist the playlist
 * \param psz_name the name of the node
 * \param p_parent the parent node to attach to or NULL if no attach
 * \param i_pos position of the node in the parent, PLAYLIST_END to append to end.
 * \param p_flags miscellaneous flags
 * \param p_input the input_item to attach to or NULL if it has to be created
 * \return the new node
 */
playlist_item_t * playlist_NodeCreate( playlist_t *p_playlist,
                                       const char *psz_name,
                                       playlist_item_t *p_parent, int i_pos,
                                       int i_flags )
{
    input_item_t *p_new_input;
    playlist_item_t *p_item;

    PL_ASSERT_LOCKED;
    if( !psz_name ) psz_name = _("Undefined");

    p_new_input = input_item_NewExt( NULL, psz_name, -1, ITEM_TYPE_NODE,
                                     ITEM_NET_UNKNOWN );
    p_item = playlist_ItemNewFromInput( p_playlist, p_new_input );
    vlc_gc_decref( p_new_input );

    if( p_item == NULL )  return NULL;
    p_item->i_children = 0;

    ARRAY_APPEND(pl_priv(p_playlist)->all_items, p_item);

    if( p_parent != NULL )
        playlist_NodeInsert( p_playlist, p_item, p_parent, i_pos );
    playlist_SendAddNotify( p_playlist, p_item,
                            !( i_flags & PLAYLIST_NO_REBUILD ));

    p_item->i_flags |= i_flags;

    return p_item;
}

/**
 * Remove all the children of a node and removes the node
 *
 * \param p_playlist the playlist
 * \param p_root the node
 */
void playlist_NodeDelete( playlist_t *p_playlist, playlist_item_t *p_root,
                          bool b_force )
{
    PL_ASSERT_LOCKED;

    /* Delete the children */
    for( int i = p_root->i_children - 1 ; i >= 0; i-- )
        playlist_NodeDelete( p_playlist, p_root->pp_children[i], b_force );

    /* Delete the node */
    if( p_root->i_flags & PLAYLIST_RO_FLAG && !b_force )
        return;

    pl_priv(p_playlist)->b_reset_currently_playing = true;

    int i;
    var_SetAddress( p_playlist, "playlist-item-deleted", p_root );
    ARRAY_BSEARCH( pl_priv(p_playlist)->all_items, ->i_id, int, p_root->i_id, i );
    if( i != -1 )
        ARRAY_REMOVE( pl_priv(p_playlist)->all_items, i );

    if( p_root->i_children == -1 ) {
        ARRAY_BSEARCH( p_playlist->items,->i_id, int, p_root->i_id, i );
        if( i != -1 )
            ARRAY_REMOVE( p_playlist->items, i );
    }

    /* Check if it is the current item */
    if( get_current_status_item( p_playlist ) == p_root )
    {
        /* Stop */
        playlist_Control( p_playlist, PLAYLIST_STOP, pl_Locked );
        msg_Info( p_playlist, "stopping playback" );
        /* This item can't be the next one to be played ! */
        set_current_status_item( p_playlist, NULL );
    }

    for( i = 0; i < p_playlist->current.i_size; i++ )
        if( p_playlist->current.p_elems[i] == p_root )
            ARRAY_REMOVE( p_playlist->current, i );
    for( i = 0; i < p_playlist->current.i_size; i++ )
        assert( p_playlist->current.p_elems[i] != p_root );

    PL_DEBUG( "deleting item `%s'", p_root->p_input->psz_name );

    /* Remove the item from its parent */
    playlist_item_t *p_parent = p_root->p_parent;
    if( p_parent != NULL )
    {
        for( int i = 0; i < p_parent->i_children ; i++ )
        {
            if( p_parent->pp_children[i] == p_root )
            {
                REMOVE_ELEM( p_parent->pp_children, p_parent->i_children, i );
                assert( p_root->p_parent == p_parent );
            }
        }
    }

    playlist_ItemRelease( p_root );
}

int playlist_NodeInsert( playlist_t *p_playlist,
                         playlist_item_t *p_item,
                         playlist_item_t *p_parent,
                         int i_position )
{
    PL_ASSERT_LOCKED;
{'fraction_non_alphanumeric': 0.15251626155426223, 'fraction_numerical': 0.005220814789455666, 'mean_word_length': 2.6142901330034025, 'pattern_counts': {'":': 0, '<': 17, '<?xml version=': 0, '>': 72, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 10, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6051172', 'n_tokens_mistral': 3760, 'n_tokens_neox': 3595, 'n_words': 980}