/***************************************************************************** * epg.c: Electronic Program Guide ***************************************************************************** * Copyright (C) 2007 VLC authors and VideoLAN * $Id$ * * Authors: Laurent Aimar * * 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. *****************************************************************************/ /***************************************************************************** * Preamble *****************************************************************************/ #ifdef HAVE_CONFIG_H # include "config.h" #endif #include #include static void vlc_epg_event_Clean(vlc_epg_event_t *p_event) { free(p_event->psz_description); free(p_event->psz_short_description); free(p_event->psz_name); } void vlc_epg_event_Delete(vlc_epg_event_t *p_event) { vlc_epg_event_Clean(p_event); free(p_event); } static void vlc_epg_event_Init(vlc_epg_event_t *p_event, uint16_t i_id, int64_t i_start, uint32_t i_duration) { memset(p_event, 0, sizeof(*p_event)); p_event->i_start = i_start; p_event->i_id = i_id; p_event->i_duration = i_duration; } vlc_epg_event_t * vlc_epg_event_New(uint16_t i_id, int64_t i_start, uint32_t i_duration) { vlc_epg_event_t *p_event = (vlc_epg_event_t *) malloc(sizeof(*p_event)); if(p_event) vlc_epg_event_Init(p_event, i_id, i_start, i_duration); return p_event; } vlc_epg_event_t * vlc_epg_event_Duplicate( const vlc_epg_event_t *p_src ) { vlc_epg_event_t *p_evt = vlc_epg_event_New( p_src->i_id, p_src->i_start, p_src->i_duration ); if( likely(p_evt) ) { if( p_src->psz_description ) p_evt->psz_description = strdup( p_src->psz_description ); if( p_src->psz_name ) p_evt->psz_name = strdup( p_src->psz_name ); if( p_src->psz_short_description ) p_evt->psz_short_description = strdup( p_src->psz_short_description ); p_evt->i_rating = p_src->i_rating; } return p_evt; } static void vlc_epg_Init( vlc_epg_t *p_epg, uint32_t i_id, uint16_t i_source_id ) { p_epg->i_id = i_id; p_epg->i_source_id = i_source_id; p_epg->psz_name = NULL; p_epg->p_current = NULL; TAB_INIT( p_epg->i_event, p_epg->pp_event ); } static void vlc_epg_Clean( vlc_epg_t *p_epg ) { size_t i; for( i = 0; i < p_epg->i_event; i++ ) vlc_epg_event_Delete( p_epg->pp_event[i] ); TAB_CLEAN( p_epg->i_event, p_epg->pp_event ); free( p_epg->psz_name ); } bool vlc_epg_AddEvent( vlc_epg_t *p_epg, vlc_epg_event_t *p_evt ) { ssize_t i_pos = -1; /* Insertions are supposed in sequential order first */ if( p_epg->i_event ) { if( p_epg->pp_event[0]->i_start > p_evt->i_start ) { i_pos = 0; } else if ( p_epg->pp_event[p_epg->i_event - 1]->i_start >= p_evt->i_start ) { /* Do bisect search lower start time entry */ size_t i_lower = 0; size_t i_upper = p_epg->i_event - 1; while( i_lower < i_upper ) { size_t i_split = ( i_lower + i_upper ) / 2; vlc_epg_event_t *p_cur = p_epg->pp_event[i_split]; if( p_cur->i_start < p_evt->i_start ) { i_lower = i_split + 1; } else if ( p_cur->i_start >= p_evt->i_start ) { i_upper = i_split; } } i_pos = i_lower; } } if( i_pos != -1 ) { /* There can be only one event at same time */ if( p_epg->pp_event[i_pos]->i_start == p_evt->i_start ) { vlc_epg_event_Delete( p_epg->pp_event[i_pos] ); if( p_epg->p_current == p_epg->pp_event[i_pos] ) p_epg->p_current = p_evt; p_epg->pp_event[i_pos] = p_evt; return true; } else { TAB_INSERT( p_epg->i_event, p_epg->pp_event, p_evt, i_pos ); } } else TAB_APPEND( p_epg->i_event, p_epg->pp_event, p_evt ); return true; } vlc_epg_t *vlc_epg_New( uint32_t i_id, uint16_t i_source_id ) { vlc_epg_t *p_epg = malloc( sizeof(*p_epg) ); if( p_epg ) vlc_epg_Init( p_epg, i_id, i_source_id ); return p_epg; } void vlc_epg_Delete( vlc_epg_t *p_epg ) { vlc_epg_Clean( p_epg ); free( p_epg ); } void vlc_epg_SetCurrent( vlc_epg_t *p_epg, int64_t i_start ) { size_t i; p_epg->p_current = NULL; if( i_start < 0 ) return; for( i = 0; i < p_epg->i_event; i++ ) { if( p_epg->pp_event[i]->i_start == i_start ) { p_epg->p_current = p_epg->pp_event[i]; break; } } } static void vlc_epg_Prune( vlc_epg_t *p_dst ) { /* Keep only 1 old event */ if( p_dst->p_current ) { while( p_dst->i_event > 1 && p_dst->pp_event[0] != p_dst->p_current && p_dst->pp_event[1] != p_dst->p_current ) { vlc_epg_event_Delete( p_dst->pp_event[0] ); TAB_ERASE( p_dst->i_event, p_dst->pp_event, 0 ); } } } void vlc_epg_Merge( vlc_epg_t *p_dst_epg, const vlc_epg_t *p_src_epg ) { if( p_src_epg->i_event == 0 ) return; size_t i_dst=0; size_t i_src=0; for( ; i_src < p_src_epg->i_event; i_src++ ) { bool b_current = ( p_src_epg->pp_event[i_src] == p_src_epg->p_current ); vlc_epg_event_t *p_src = vlc_epg_event_Duplicate( p_src_epg->pp_event[i_src] ); if( unlikely(!p_src) ) return; const int64_t i_src_end = p_src->i_start + p_src->i_duration; while( i_dst < p_dst_epg->i_event ) { vlc_epg_event_t *p_dst = p_dst_epg->pp_event[i_dst]; const int64_t i_dst_end = p_dst->i_start + p_dst->i_duration; /* appended is before current, no overlap */ if( p_dst->i_start >= i_src_end ) { break; } /* overlap case: appended would contain current's start (or are identical) */ else if( ( p_dst->i_start >= p_src->i_start && p_dst->i_start < i_src_end ) || /* overlap case: appended would contain current's end */ ( i_dst_end > p_src->i_start && i_dst_end <= i_src_end ) ) { vlc_epg_event_Delete( p_dst ); if( p_dst_epg->p_current == p_dst ) { b_current |= true; p_dst_epg->p_current = NULL; } TAB_ERASE( p_dst_epg->i_event, p_dst_epg->pp_event, i_dst ); } else { i_dst++; } } TAB_INSERT( p_dst_epg->i_event, p_dst_epg->pp_event, p_src, i_dst ); if( b_current ) p_dst_epg->p_current = p_src; } /* Remaining/trailing ones */ for( ; i_src < p_src_epg->i_event; i_src++ ) { vlc_epg_event_t *p_src = vlc_epg_event_Duplicate( p_src_epg->pp_event[i_src] ); if( unlikely(!p_src) ) return; TAB_APPEND( p_dst_epg->i_event, p_dst_epg->pp_event, p_src ); if( p_src_epg->pp_event[i_src] == p_src_epg->p_current ) p_dst_epg->p_current = p_src; } vlc_epg_Prune( p_dst_epg ); } vlc_epg_t * vlc_epg_Duplicate( const vlc_epg_t *p_src ) { vlc_epg_t *p_epg = vlc_epg_New( p_src->i_id, p_src->i_source_id ); if( p_epg ) { p_epg->psz_name = ( p_src->psz_name ) ? strdup( p_src->psz_name ) : NULL; for( size_t i=0; ii_event; i++ ) { vlc_epg_event_t *p_dup = vlc_epg_event_Duplicate( p_src->pp_event[i] ); if( p_dup ) { if( p_src->p_current == p_src->pp_event[i] ) p_epg->p_current = p_dup; TAB_APPEND( p_epg->i_event, p_epg->pp_event, p_dup ); } } } return p_epg; }