Coverage Report

Created: 2025-07-18 07:04

/src/vlc/modules/demux/mkv/chapters.cpp
Line
Count
Source (jump to first uncovered line)
1
/*****************************************************************************
2
 * chapters.cpp : matroska demuxer
3
 *****************************************************************************
4
 * Copyright (C) 2003-2004 VLC authors and VideoLAN
5
 *
6
 * Authors: Laurent Aimar <fenrir@via.ecp.fr>
7
 *          Steve Lhomme <steve.lhomme@free.fr>
8
 *
9
 * This program is free software; you can redistribute it and/or modify it
10
 * under the terms of the GNU Lesser General Public License as published by
11
 * the Free Software Foundation; either version 2.1 of the License, or
12
 * (at your option) any later version.
13
 *
14
 * This program is distributed in the hope that it will be useful,
15
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17
 * GNU Lesser General Public License for more details.
18
 *
19
 * You should have received a copy of the GNU Lesser General Public License
20
 * along with this program; if not, write to the Free Software Foundation,
21
 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22
 *****************************************************************************/
23
24
#include "chapters.hpp"
25
26
#include "chapter_command.hpp"
27
28
#include <vlc_arrays.h>
29
30
#include <functional>
31
#include <algorithm>
32
33
namespace mkv {
34
35
chapter_item_c::~chapter_item_c()
36
0
{
37
0
    delete p_segment_uid;
38
0
    delete p_segment_edition_uid;
39
0
    vlc_delete_all( codecs );
40
0
    vlc_delete_all( sub_chapters );
41
0
}
42
43
chapter_item_c *chapter_item_c::BrowseCodecPrivate( chapter_codec_id codec_id,
44
                                                    chapter_cmd_match match )
45
0
{
46
    // this chapter
47
0
    for (const mkv::chapter_codec_cmds_c *index : codecs)
48
0
    {
49
0
        if ( index->i_codec_id == codec_id &&
50
0
             match( *index ) )
51
0
            return this;
52
0
    }
53
0
    return NULL;
54
0
}
55
56
void chapter_item_c::Append( const chapter_item_c & chapter )
57
0
{
58
    // we are appending content for the same chapter UID
59
0
    size_t i;
60
0
    chapter_item_c *p_chapter;
61
62
0
    for ( i=0; i<chapter.sub_chapters.size(); i++ )
63
0
    {
64
0
        p_chapter = FindChapter( chapter.sub_chapters[i]->i_uid );
65
0
        if ( p_chapter != NULL )
66
0
        {
67
0
            p_chapter->Append( *chapter.sub_chapters[i] );
68
0
        }
69
0
        else
70
0
        {
71
0
            sub_chapters.push_back( chapter.sub_chapters[i] );
72
0
        }
73
0
    }
74
0
}
75
76
chapter_item_c * chapter_item_c::FindChapter( chapter_uid i_find_uid )
77
0
{
78
0
    size_t i;
79
0
    chapter_item_c *p_result = NULL;
80
81
0
    if ( i_uid == i_find_uid )
82
0
        return this;
83
84
0
    for ( i=0; i<sub_chapters.size(); i++)
85
0
    {
86
0
        p_result = sub_chapters[i]->FindChapter( i_find_uid );
87
0
        if ( p_result != NULL )
88
0
            break;
89
0
    }
90
0
    return p_result;
91
0
}
92
93
std::string chapter_item_c::GetCodecName( bool f_for_title ) const
94
0
{
95
0
    std::string result;
96
97
0
    for (const mkv::chapter_codec_cmds_c *index : codecs)
98
0
    {
99
0
        result = index->GetCodecName( f_for_title );
100
0
        if ( !result.empty () )
101
0
            break;
102
0
    }
103
104
0
    return result;
105
0
}
106
107
int16_t chapter_item_c::GetTitleNumber( ) const
108
0
{
109
0
    int result = -1;
110
111
0
    for (const mkv::chapter_codec_cmds_c *index : codecs)
112
0
    {
113
0
        result = index->GetTitleNumber( );
114
0
        if ( result >= 0 )
115
0
            break;
116
0
    }
117
118
0
    return result;
119
0
}
120
121
bool chapter_item_c::ParentOf( const chapter_item_c & item ) const
122
0
{
123
0
    if ( &item == this )
124
0
        return true;
125
126
0
    std::vector<chapter_item_c*>::const_iterator index = sub_chapters.begin();
127
0
    while ( index != sub_chapters.end() )
128
0
    {
129
0
        if ( (*index)->ParentOf( item ) )
130
0
            return true;
131
0
        ++index;
132
0
    }
133
134
0
    return false;
135
0
}
136
137
bool chapter_item_c::EnterLeaveHelper_ ( bool do_subs,
138
    bool (chapter_codec_cmds_c::* co_cb) (),
139
    bool (chapter_item_c      ::* ch_cb) (bool)
140
0
) {
141
0
    bool f_result = false;
142
143
0
    f_result |= std::count_if ( codecs.begin (), codecs.end (),
144
0
      std::mem_fn (co_cb)
145
0
    );
146
147
0
    if ( do_subs )
148
0
    {
149
0
        using std::placeholders::_1;
150
0
        f_result |= count_if ( sub_chapters.begin (), sub_chapters.end (),
151
0
          std::bind( std::mem_fn( ch_cb ), _1, true )
152
0
        );
153
0
    }
154
155
0
    return f_result;
156
0
}
157
158
bool chapter_item_c::Enter( bool b_do_subs )
159
0
{
160
0
    return EnterLeaveHelper_ (b_do_subs,
161
0
      &chapter_codec_cmds_c::Enter,
162
0
      &chapter_item_c::Enter
163
0
    );
164
0
}
165
166
bool chapter_item_c::Leave( bool b_do_subs )
167
0
{
168
0
    b_is_leaving = true;
169
170
0
    bool f_result = EnterLeaveHelper_ (b_do_subs,
171
0
      &chapter_codec_cmds_c::Leave,
172
0
      &chapter_item_c::Leave
173
0
    );
174
175
0
    b_is_leaving = false;
176
0
    return f_result;
177
0
}
178
179
bool chapter_item_c::EnterAndLeave( chapter_item_c *p_leaving_chapter, bool b_final_enter )
180
0
{
181
0
    chapter_item_c *p_common_parent = p_leaving_chapter;
182
183
    // leave, up to a common parent
184
0
    while ( p_common_parent != NULL && !p_common_parent->ParentOf( *this ) )
185
0
    {
186
0
        if ( !p_common_parent->b_is_leaving && p_common_parent->Leave( false ) )
187
0
            return true;
188
0
        p_common_parent = p_common_parent->p_parent;
189
0
    }
190
191
    // enter from the parent to <this>
192
0
    if ( p_common_parent != NULL )
193
0
    {
194
0
        do
195
0
        {
196
0
            if ( p_common_parent == this )
197
0
                return Enter( true );
198
199
0
            for ( size_t i = 0; i<p_common_parent->sub_chapters.size(); i++ )
200
0
            {
201
0
                if ( p_common_parent->sub_chapters[i]->ParentOf( *this ) )
202
0
                {
203
0
                    p_common_parent = p_common_parent->sub_chapters[i];
204
0
                    if ( p_common_parent != this )
205
0
                        if ( p_common_parent->Enter( false ) )
206
0
                            return true;
207
208
0
                    break;
209
0
                }
210
0
            }
211
0
        } while ( 1 );
212
0
    }
213
214
0
    if ( b_final_enter )
215
0
        return Enter( true );
216
0
    else
217
0
        return false;
218
0
}
219
220
221
222
/* Chapter Edition Class */
223
std::string chapter_edition_c::GetMainName() const
224
0
{
225
0
    if ( sub_chapters.size() )
226
0
    {
227
0
        return sub_chapters[0]->GetCodecName( true );
228
0
    }
229
0
    return "";
230
0
}
231
232
} // namespace