Coverage Report

Created: 2025-07-11 06:54

/src/flac/src/libFLAC/ogg_decoder_aspect.c
Line
Count
Source (jump to first uncovered line)
1
/* libFLAC - Free Lossless Audio Codec
2
 * Copyright (C) 2002-2009  Josh Coalson
3
 * Copyright (C) 2011-2025  Xiph.Org Foundation
4
 *
5
 * Redistribution and use in source and binary forms, with or without
6
 * modification, are permitted provided that the following conditions
7
 * are met:
8
 *
9
 * - Redistributions of source code must retain the above copyright
10
 * notice, this list of conditions and the following disclaimer.
11
 *
12
 * - Redistributions in binary form must reproduce the above copyright
13
 * notice, this list of conditions and the following disclaimer in the
14
 * documentation and/or other materials provided with the distribution.
15
 *
16
 * - Neither the name of the Xiph.org Foundation nor the names of its
17
 * contributors may be used to endorse or promote products derived from
18
 * this software without specific prior written permission.
19
 *
20
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21
 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23
 * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
24
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
27
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
28
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
29
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
30
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31
 */
32
33
#ifdef HAVE_CONFIG_H
34
#  include <config.h>
35
#endif
36
37
#include <string.h> /* for memcpy() */
38
#include "FLAC/assert.h"
39
#include "share/alloc.h" /* for free() */
40
#include "private/ogg_decoder_aspect.h"
41
#include "private/ogg_mapping.h"
42
#include "private/macros.h"
43
44
static FLAC__OggDecoderAspectReadStatus read_more_data_(FLAC__OggDecoderAspect *aspect, FLAC__OggDecoderAspectReadCallbackProxy read_callback, size_t bytes_requested, const FLAC__StreamDecoder *decoder, void *client_data);
45
46
/***********************************************************************
47
 *
48
 * Public class methods
49
 *
50
 ***********************************************************************/
51
52
static FLAC__OggDecoderAspectReadStatus read_more_data_(FLAC__OggDecoderAspect *aspect, FLAC__OggDecoderAspectReadCallbackProxy read_callback, size_t bytes_requested, const FLAC__StreamDecoder *decoder, void *client_data)
53
135k
{
54
135k
  static const size_t OGG_BYTES_CHUNK = 8192;
55
135k
  const size_t ogg_bytes_to_read = flac_max(bytes_requested, OGG_BYTES_CHUNK);
56
135k
  char *oggbuf = ogg_sync_buffer(&aspect->sync_state, ogg_bytes_to_read);
57
58
135k
  if(0 == oggbuf) {
59
0
    return FLAC__OGG_DECODER_ASPECT_READ_STATUS_MEMORY_ALLOCATION_ERROR;
60
0
  }
61
135k
  else {
62
135k
    size_t ogg_bytes_read = ogg_bytes_to_read;
63
64
135k
    switch(read_callback(decoder, (FLAC__byte*)oggbuf, &ogg_bytes_read, client_data)) {
65
105k
      case FLAC__OGG_DECODER_ASPECT_READ_STATUS_OK:
66
105k
        break;
67
21.8k
      case FLAC__OGG_DECODER_ASPECT_READ_STATUS_END_OF_STREAM:
68
21.8k
        aspect->end_of_stream = true;
69
21.8k
        break;
70
7.93k
      case FLAC__OGG_DECODER_ASPECT_READ_STATUS_ABORT:
71
7.93k
        return FLAC__OGG_DECODER_ASPECT_READ_STATUS_ABORT;
72
0
      default:
73
0
        FLAC__ASSERT(0);
74
135k
    }
75
76
127k
    if(ogg_sync_wrote(&aspect->sync_state, ogg_bytes_read) < 0) {
77
      /* double protection; this will happen if the read callback returns more bytes than the max requested, which would overflow Ogg's internal buffer */
78
0
      FLAC__ASSERT(0);
79
0
      return FLAC__OGG_DECODER_ASPECT_READ_STATUS_ERROR;
80
0
    }
81
127k
  }
82
127k
  return FLAC__OGG_DECODER_ASPECT_READ_STATUS_OK;
83
135k
}
84
85
static FLAC__OggDecoderAspectReadStatus process_page_(FLAC__OggDecoderAspect *aspect, FLAC__StreamDecoderTellCallback tell_callback, const FLAC__StreamDecoder *decoder, void *client_data)
86
728k
{
87
  /* got a page, grab the serial number if necessary */
88
728k
  if(aspect->need_serial_number) {
89
    /* Check whether not FLAC. The next if is somewhat confusing: check
90
     * whether the length of the next page body agrees with the length
91
     * of a FLAC 'header' possibly contained in that page */
92
692k
    if(aspect->working_page.body_len > (long)(1 + FLAC__OGG_MAPPING_MAGIC_LENGTH) &&
93
692k
       aspect->working_page.body[0] == FLAC__OGG_MAPPING_FIRST_HEADER_PACKET_TYPE &&
94
692k
       memcmp((&aspect->working_page.body) + 1, FLAC__OGG_MAPPING_MAGIC, FLAC__OGG_MAPPING_MAGIC_LENGTH)) {
95
4.92k
      aspect->bos_flag_seen = true;
96
4.92k
      aspect->serial_number = ogg_page_serialno(&aspect->working_page);
97
4.92k
      ogg_stream_reset_serialno(&aspect->stream_state, aspect->serial_number);
98
4.92k
      aspect->need_serial_number = false;
99
100
4.92k
      if(aspect->current_linknumber_advance_read >= aspect->number_of_links_detected) {
101
1.97k
        FLAC__uint64 tell_offset;
102
1.97k
        aspect->number_of_links_detected = aspect->current_linknumber_advance_read + 1;
103
1.97k
        aspect->linkdetails[aspect->current_linknumber_advance_read].serial_number = aspect->serial_number;
104
1.97k
        if(tell_callback != 0) {
105
1.85k
          if(tell_callback(decoder, &tell_offset, client_data) == FLAC__STREAM_DECODER_TELL_STATUS_OK)
106
1.60k
            aspect->linkdetails[aspect->current_linknumber_advance_read].start_byte = tell_offset - aspect->sync_state.fill + aspect->sync_state.returned
107
1.60k
                                                                                      - aspect->working_page.header_len - aspect->working_page.body_len;
108
1.85k
        }
109
1.97k
      }
110
4.92k
    }
111
692k
  }
112
728k
  if(aspect->beginning_of_link) {
113
673k
    if(aspect->bos_flag_seen && !ogg_page_bos(&aspect->working_page)) {
114
      /* Page does not have BOS flag, which means we're done scanning for other serial numbers */
115
6.03k
      aspect->beginning_of_link = false;
116
6.03k
    }
117
673k
  }
118
728k
  if(ogg_stream_pagein(&aspect->stream_state, &aspect->working_page) == 0) {
119
206k
    aspect->have_working_page = true;
120
206k
    aspect->have_working_packet = false;
121
206k
  }
122
522k
  else if(aspect->beginning_of_link) {
123
    /* At the beginning of a link, store the serial numbers of all other streams, to make
124
     * finding the end of a link through seeking possible */
125
494k
    if(ogg_page_bos(&aspect->working_page)) {
126
487k
      aspect->bos_flag_seen = true;
127
487k
      if(aspect->current_linknumber_advance_read >= aspect->number_of_links_indexed) {
128
481k
        FLAC__OggDecoderAspect_LinkDetails * current_link = &aspect->linkdetails[aspect->current_linknumber_advance_read];
129
        /* Reallocate in chunks of 4 */
130
481k
        if((current_link->number_of_other_streams) % 4 == 0) {
131
121k
          long * tmpptr = NULL;
132
121k
          if(NULL == (tmpptr = safe_realloc_nofree_mul_2op_(current_link->other_serial_numbers, 4+current_link->number_of_other_streams, sizeof(long)))) {
133
72
            return FLAC__OGG_DECODER_ASPECT_READ_STATUS_MEMORY_ALLOCATION_ERROR;
134
72
          }
135
121k
          current_link->other_serial_numbers = tmpptr;
136
121k
        }
137
481k
        current_link->other_serial_numbers[current_link->number_of_other_streams] = ogg_page_serialno(&aspect->working_page);
138
481k
        current_link->number_of_other_streams++;
139
481k
      }
140
487k
    }
141
    /* No BOS flag seen yet, these pages might be still from previous link */
142
494k
  }
143
  /* else do nothing, could be a page from another stream */
144
728k
  return FLAC__OGG_DECODER_ASPECT_READ_STATUS_OK;
145
728k
}
146
147
static FLAC__bool check_size_of_link_allocation_(FLAC__OggDecoderAspect *aspect)
148
100k
{
149
  /* double on reallocating */
150
100k
  if(aspect->current_linknumber >= aspect->number_of_links_allocated || aspect->current_linknumber_advance_read >= aspect->number_of_links_allocated) {
151
953
    FLAC__OggDecoderAspect_LinkDetails * tmpptr = NULL;
152
953
    if(NULL == (tmpptr = safe_realloc_nofree_mul_2op_(aspect->linkdetails,2*aspect->number_of_links_allocated,sizeof(FLAC__OggDecoderAspect_LinkDetails)))) {
153
4
      return false;
154
4
    }
155
949
    aspect->linkdetails = tmpptr;
156
949
    memset(aspect->linkdetails + aspect->number_of_links_allocated, 0, aspect->number_of_links_allocated * sizeof(FLAC__OggDecoderAspect_LinkDetails));
157
949
    aspect->number_of_links_allocated *= 2;
158
949
  }
159
100k
  return true;
160
100k
}
161
162
FLAC__bool FLAC__ogg_decoder_aspect_init(FLAC__OggDecoderAspect *aspect)
163
10.9k
{
164
  /* we will determine the serial number later if necessary */
165
10.9k
  if(ogg_stream_init(&aspect->stream_state, aspect->serial_number) != 0)
166
0
    return false;
167
168
10.9k
  if(ogg_sync_init(&aspect->sync_state) != 0)
169
0
    return false;
170
171
10.9k
  aspect->version_major = ~(0u);
172
10.9k
  aspect->version_minor = ~(0u);
173
174
10.9k
  aspect->need_serial_number = aspect->use_first_serial_number || aspect->decode_chained_stream;
175
176
10.9k
  aspect->end_of_stream = false;
177
10.9k
  aspect->have_working_page = false;
178
10.9k
  aspect->end_of_link = false;
179
180
10.9k
  aspect->current_linknumber = 0;
181
10.9k
  aspect->current_linknumber_advance_read = 0;
182
10.9k
  aspect->number_of_links_indexed = 0;
183
10.9k
  aspect->number_of_links_detected = 0;
184
10.9k
  aspect->number_of_links_allocated = 0;
185
186
10.9k
  if(NULL == (aspect->linkdetails = safe_realloc_mul_2op_(NULL,4,sizeof(FLAC__OggDecoderAspect_LinkDetails))))
187
6
    return false;
188
10.9k
  memset(aspect->linkdetails, 0, 4 * sizeof(FLAC__OggDecoderAspect_LinkDetails));
189
190
10.9k
  aspect->number_of_links_allocated = 4;
191
192
10.9k
  return true;
193
10.9k
}
194
195
void FLAC__ogg_decoder_aspect_finish(FLAC__OggDecoderAspect *aspect)
196
10.9k
{
197
10.9k
  uint32_t i;
198
10.9k
  (void)ogg_sync_clear(&aspect->sync_state);
199
10.9k
  (void)ogg_stream_clear(&aspect->stream_state);
200
10.9k
  if(NULL != aspect->linkdetails) {
201
117k
    for(i = 0; i < aspect->number_of_links_allocated; i++)
202
106k
      free(aspect->linkdetails[i].other_serial_numbers);
203
10.9k
    free(aspect->linkdetails);
204
10.9k
  }
205
10.9k
  aspect->linkdetails = NULL;
206
10.9k
}
207
208
void FLAC__ogg_decoder_aspect_set_serial_number(FLAC__OggDecoderAspect *aspect, long value)
209
249
{
210
249
  aspect->use_first_serial_number = false;
211
249
  aspect->serial_number = value;
212
249
}
213
214
void FLAC__ogg_decoder_aspect_set_defaults(FLAC__OggDecoderAspect *aspect)
215
310k
{
216
310k
  aspect->use_first_serial_number = true;
217
310k
  aspect->decode_chained_stream = false;
218
310k
}
219
220
void FLAC__ogg_decoder_aspect_flush(FLAC__OggDecoderAspect *aspect)
221
86.6k
{
222
86.6k
  (void)ogg_stream_reset(&aspect->stream_state);
223
86.6k
  (void)ogg_sync_reset(&aspect->sync_state);
224
86.6k
  aspect->end_of_stream = false;
225
86.6k
  aspect->have_working_page = false;
226
86.6k
  aspect->end_of_link = false;
227
86.6k
}
228
229
void FLAC__ogg_decoder_aspect_reset(FLAC__OggDecoderAspect *aspect)
230
29.7k
{
231
29.7k
  FLAC__ogg_decoder_aspect_flush(aspect);
232
29.7k
  aspect->current_linknumber = 0;
233
29.7k
  aspect->current_linknumber_advance_read = 0;
234
235
29.7k
  if(aspect->use_first_serial_number || aspect->decode_chained_stream)
236
29.7k
    aspect->need_serial_number = true;
237
238
29.7k
  aspect->beginning_of_link = true;
239
29.7k
  aspect->bos_flag_seen = false;
240
29.7k
}
241
242
void FLAC__ogg_decoder_aspect_next_link(FLAC__OggDecoderAspect* aspect)
243
68.2k
{
244
68.2k
  aspect->end_of_link = false;
245
68.2k
  aspect->current_linknumber++;
246
68.2k
  aspect->beginning_of_link = true;
247
68.2k
  aspect->bos_flag_seen = false;
248
68.2k
}
249
250
void FLAC__ogg_decoder_aspect_set_decode_chained_stream(FLAC__OggDecoderAspect* aspect, FLAC__bool value)
251
23.4k
{
252
23.4k
  aspect->decode_chained_stream = value;
253
23.4k
}
254
255
FLAC__bool FLAC__ogg_decoder_aspect_get_decode_chained_stream(FLAC__OggDecoderAspect* aspect)
256
28.7k
{
257
28.7k
  return aspect->decode_chained_stream;
258
28.7k
}
259
260
FLAC__OggDecoderAspect_TargetLink * FLAC__ogg_decoder_aspect_get_target_link(FLAC__OggDecoderAspect* aspect, FLAC__uint64 target_sample)
261
4.24k
{
262
  /* This returns the link containing the seek target if known. In
263
   * effect, this function always returns NULL if no links have been
264
   * indexed */
265
266
4.24k
  uint32_t current_link = 0;
267
4.24k
  uint32_t total_samples = 0;
268
269
1.38M
  while(current_link < aspect->number_of_links_indexed) {
270
1.38M
    total_samples += aspect->linkdetails[current_link].samples;
271
1.38M
    if(target_sample < total_samples) {
272
1.29k
      aspect->target_link.serial_number = aspect->linkdetails[current_link].serial_number;
273
1.29k
      aspect->target_link.start_byte = aspect->linkdetails[current_link].start_byte;
274
1.29k
      aspect->target_link.samples_in_preceding_links = total_samples - aspect->linkdetails[current_link].samples;
275
1.29k
      aspect->target_link.end_byte = aspect->linkdetails[current_link].end_byte;
276
1.29k
      aspect->target_link.samples_this_link = aspect->linkdetails[current_link].samples;
277
1.29k
      aspect->target_link.linknumber = current_link;
278
1.29k
      return &aspect->target_link;
279
1.29k
    }
280
1.38M
    current_link++;
281
1.38M
  }
282
2.94k
  return NULL;
283
4.24k
}
284
285
void FLAC__ogg_decoder_aspect_set_seek_parameters(FLAC__OggDecoderAspect *aspect, FLAC__OggDecoderAspect_TargetLink *target_link)
286
1.55k
{
287
1.55k
  if(target_link == 0) {
288
254
    aspect->is_seeking = false;
289
254
  }
290
1.29k
  else {
291
1.29k
    aspect->need_serial_number = false;
292
1.29k
    aspect->current_linknumber = target_link->linknumber;
293
1.29k
    aspect->current_linknumber_advance_read = target_link->linknumber;
294
1.29k
    aspect->serial_number = target_link->serial_number;
295
1.29k
    ogg_stream_reset_serialno(&aspect->stream_state, aspect->serial_number);
296
1.29k
    aspect->is_seeking = true;
297
1.29k
  }
298
1.55k
}
299
300
301
FLAC__OggDecoderAspectReadStatus FLAC__ogg_decoder_aspect_read_callback_wrapper(FLAC__OggDecoderAspect *aspect, FLAC__byte buffer[], size_t *bytes, FLAC__OggDecoderAspectReadCallbackProxy read_callback, FLAC__StreamDecoderTellCallback tell_callback, const FLAC__StreamDecoder *decoder, void *client_data)
302
483k
{
303
483k
  const size_t bytes_requested = *bytes;
304
305
483k
  const uint32_t header_length =
306
483k
    FLAC__OGG_MAPPING_PACKET_TYPE_LENGTH +
307
483k
    FLAC__OGG_MAPPING_MAGIC_LENGTH +
308
483k
    FLAC__OGG_MAPPING_VERSION_MAJOR_LENGTH +
309
483k
    FLAC__OGG_MAPPING_VERSION_MINOR_LENGTH +
310
483k
    FLAC__OGG_MAPPING_NUM_HEADERS_LENGTH;
311
312
  /*
313
   * The FLAC decoding API uses pull-based reads, whereas Ogg decoding
314
   * is push-based.  In libFLAC, when you ask to decode a frame, the
315
   * decoder will eventually call the read callback to supply some data,
316
   * but how much it asks for depends on how much free space it has in
317
   * its internal buffer.  It does not try to grow its internal buffer
318
   * to accommodate a whole frame because then the internal buffer size
319
   * could not be limited, which is necessary in embedded applications.
320
   *
321
   * Ogg however grows its internal buffer until a whole page is present;
322
   * only then can you get decoded data out.  So we can't just ask for
323
   * the same number of bytes from Ogg, then pass what's decoded down to
324
   * libFLAC.  If what libFLAC is asking for will not contain a whole
325
   * page, then we will get no data from ogg_sync_pageout(), and at the
326
   * same time cannot just read more data from the client for the purpose
327
   * of getting a whole decoded page because the decoded size might be
328
   * larger than libFLAC's internal buffer.
329
   *
330
   * Instead, whenever this read callback wrapper is called, we will
331
   * continually request data from the client until we have at least one
332
   * page, and manage pages internally so that we can send pieces of
333
   * pages down to libFLAC in such a way that we obey its size
334
   * requirement.  To limit the amount of callbacks, we will always try
335
   * to read in enough pages to return the full number of bytes
336
   * requested.
337
   */
338
483k
  *bytes = 0;
339
4.13M
  while (*bytes < bytes_requested && !aspect->end_of_stream) {
340
4.09M
    if (aspect->end_of_link && aspect->have_working_page) {
341
      /* we've now consumed all packets of this link and have checked that a new page follows it */
342
71.9k
      if(*bytes > 0)
343
3.08k
        return FLAC__OGG_DECODER_ASPECT_READ_STATUS_OK;
344
68.8k
      else
345
68.8k
        return FLAC__OGG_DECODER_ASPECT_READ_STATUS_END_OF_LINK;
346
71.9k
    }
347
4.02M
    else if (aspect->have_working_page) {
348
3.03M
      if (aspect->have_working_packet) {
349
1.41M
        size_t n = bytes_requested - *bytes;
350
1.41M
        if ((size_t)aspect->working_packet.bytes <= n) {
351
          /* the rest of the packet will fit in the buffer */
352
1.41M
          n = aspect->working_packet.bytes;
353
1.41M
          memcpy(buffer, aspect->working_packet.packet, n);
354
1.41M
          *bytes += n;
355
1.41M
          buffer += n;
356
1.41M
          aspect->have_working_packet = false;
357
1.41M
          if(aspect->working_packet.e_o_s) {
358
77.6k
            if(!aspect->decode_chained_stream)
359
3.57k
              aspect->end_of_stream = true;
360
74.0k
            else {
361
74.0k
              aspect->end_of_link = true;
362
74.0k
              aspect->current_linknumber_advance_read = aspect->current_linknumber + 1;
363
74.0k
              if(!check_size_of_link_allocation_(aspect))
364
3
                return FLAC__OGG_DECODER_ASPECT_READ_STATUS_MEMORY_ALLOCATION_ERROR;
365
74.0k
              if(aspect->current_linknumber >= aspect->number_of_links_indexed) {
366
45.8k
                FLAC__uint64 tell_offset;
367
45.8k
                FLAC__ASSERT(aspect->current_linknumber == aspect->number_of_links_indexed);
368
45.8k
                aspect->linkdetails[aspect->current_linknumber].samples = aspect->working_packet.granulepos;
369
45.8k
                if(tell_callback != 0) {
370
45.7k
                  if(tell_callback(decoder, &tell_offset, client_data) == FLAC__STREAM_DECODER_TELL_STATUS_OK)
371
41.8k
                    aspect->linkdetails[aspect->current_linknumber].end_byte = tell_offset - aspect->sync_state.fill + aspect->sync_state.returned;
372
45.7k
                }
373
45.8k
                aspect->number_of_links_indexed++;
374
45.8k
                aspect->need_serial_number = true;
375
45.8k
              }
376
74.0k
              if(!aspect->is_seeking)
377
61.4k
                aspect->need_serial_number = true;
378
74.0k
              aspect->have_working_page = false; /* e-o-s packet ends page */
379
74.0k
            }
380
77.6k
          }
381
1.41M
        }
382
4.56k
        else {
383
          /* only n bytes of the packet will fit in the buffer */
384
4.56k
          memcpy(buffer, aspect->working_packet.packet, n);
385
4.56k
          *bytes += n;
386
4.56k
          buffer += n;
387
4.56k
          aspect->working_packet.packet += n;
388
4.56k
          aspect->working_packet.bytes -= n;
389
4.56k
        }
390
1.41M
      }
391
1.61M
      else {
392
        /* try and get another packet */
393
1.61M
        const int ret = ogg_stream_packetout(&aspect->stream_state, &aspect->working_packet);
394
1.61M
        if (ret > 0) {
395
1.41M
          aspect->have_working_packet = true;
396
          /* if it is the first header packet, check for magic and a supported Ogg FLAC mapping version */
397
1.41M
          if (aspect->working_packet.bytes > 0 && aspect->working_packet.packet[0] == FLAC__OGG_MAPPING_FIRST_HEADER_PACKET_TYPE) {
398
5.56k
            const FLAC__byte *b = aspect->working_packet.packet;
399
5.56k
            if (aspect->working_packet.bytes < (long)header_length)
400
529
              return FLAC__OGG_DECODER_ASPECT_READ_STATUS_NOT_FLAC;
401
5.03k
            b += FLAC__OGG_MAPPING_PACKET_TYPE_LENGTH;
402
5.03k
            if (memcmp(b, FLAC__OGG_MAPPING_MAGIC, FLAC__OGG_MAPPING_MAGIC_LENGTH))
403
256
              return FLAC__OGG_DECODER_ASPECT_READ_STATUS_NOT_FLAC;
404
4.78k
            b += FLAC__OGG_MAPPING_MAGIC_LENGTH;
405
4.78k
            aspect->version_major = (uint32_t)(*b);
406
4.78k
            b += FLAC__OGG_MAPPING_VERSION_MAJOR_LENGTH;
407
4.78k
            aspect->version_minor = (uint32_t)(*b);
408
4.78k
            if (aspect->version_major != 1)
409
505
              return FLAC__OGG_DECODER_ASPECT_READ_STATUS_UNSUPPORTED_MAPPING_VERSION;
410
4.27k
            aspect->working_packet.packet += header_length;
411
4.27k
            aspect->working_packet.bytes -= header_length;
412
4.27k
          }
413
1.41M
        }
414
197k
        else if (ret == 0) {
415
73.8k
          aspect->have_working_page = false;
416
73.8k
        }
417
123k
        else { /* ret < 0 */
418
          /* lost sync, we'll leave the working page for the next call */
419
123k
          return FLAC__OGG_DECODER_ASPECT_READ_STATUS_LOST_SYNC;
420
123k
        }
421
1.61M
      }
422
3.03M
    }
423
992k
    else {
424
      /* try and get another page */
425
992k
      const int ret = ogg_sync_pageout(&aspect->sync_state, &aspect->working_page);
426
992k
      if (ret > 0) {
427
624k
        FLAC__OggDecoderAspectReadStatus status = process_page_(aspect, tell_callback, decoder, client_data);
428
624k
        if(status != FLAC__OGG_DECODER_ASPECT_READ_STATUS_OK)
429
21
          return status;
430
624k
      }
431
367k
      else if (ret == 0) {
432
        /* need more data */
433
123k
        FLAC__OggDecoderAspectReadStatus status = read_more_data_(aspect, read_callback, bytes_requested - *bytes, decoder, client_data);
434
123k
        if(status != FLAC__OGG_DECODER_ASPECT_READ_STATUS_OK)
435
7.93k
          return status;
436
123k
      }
437
244k
      else { /* ret < 0 */
438
        /* lost sync, bail out */
439
244k
        return FLAC__OGG_DECODER_ASPECT_READ_STATUS_LOST_SYNC;
440
244k
      }
441
992k
    }
442
4.09M
  }
443
444
35.0k
  if (aspect->end_of_stream && *bytes == 0) {
445
21.8k
    aspect->linkdetails[aspect->current_linknumber].is_last = true;
446
21.8k
    return FLAC__OGG_DECODER_ASPECT_READ_STATUS_END_OF_STREAM;
447
21.8k
  }
448
449
13.2k
  return FLAC__OGG_DECODER_ASPECT_READ_STATUS_OK;
450
35.0k
}
451
452
FLAC__OggDecoderAspectReadStatus FLAC__ogg_decoder_aspect_skip_link(FLAC__OggDecoderAspect *aspect, FLAC__OggDecoderAspectReadCallbackProxy read_callback, FLAC__StreamDecoderSeekCallback seek_callback, FLAC__StreamDecoderTellCallback tell_callback, FLAC__StreamDecoderLengthCallback length_callback, const FLAC__StreamDecoder *decoder, void *client_data)
453
14.9k
{
454
14.9k
  if(seek_callback == NULL || tell_callback == NULL || length_callback == NULL)
455
0
    return FLAC__OGG_DECODER_ASPECT_READ_STATUS_CALLBACKS_NONFUNCTIONAL;
456
457
  /* This extra check is here, because allocation failures while reading cannot always be
458
   * properly passed down the chain with the current API. So, instead, check again */
459
14.9k
  if(!check_size_of_link_allocation_(aspect))
460
0
    return FLAC__OGG_DECODER_ASPECT_READ_STATUS_MEMORY_ALLOCATION_ERROR;
461
462
14.9k
  if(aspect->current_linknumber < aspect->number_of_links_indexed) {
463
11.1k
    if(aspect->linkdetails[aspect->current_linknumber].is_last) {
464
      /* Seek to end of stream */
465
766
      FLAC__StreamDecoderLengthStatus lstatus;
466
766
      FLAC__StreamDecoderSeekStatus sstatus;
467
766
      uint64_t stream_length = 0;
468
469
766
      lstatus = length_callback(decoder, &stream_length, client_data);
470
766
      if(lstatus == FLAC__STREAM_DECODER_LENGTH_STATUS_UNSUPPORTED)
471
0
        return FLAC__OGG_DECODER_ASPECT_READ_STATUS_CALLBACKS_NONFUNCTIONAL;
472
766
      if(lstatus == FLAC__STREAM_DECODER_LENGTH_STATUS_ERROR)
473
0
        return FLAC__OGG_DECODER_ASPECT_READ_STATUS_ERROR;
474
475
766
      sstatus = seek_callback(decoder, stream_length, client_data);
476
766
      if(sstatus == FLAC__STREAM_DECODER_SEEK_STATUS_UNSUPPORTED)
477
0
        return FLAC__OGG_DECODER_ASPECT_READ_STATUS_CALLBACKS_NONFUNCTIONAL;
478
766
      if(sstatus == FLAC__STREAM_DECODER_SEEK_STATUS_ERROR)
479
0
        return FLAC__OGG_DECODER_ASPECT_READ_STATUS_ERROR;
480
481
766
      return FLAC__OGG_DECODER_ASPECT_READ_STATUS_END_OF_STREAM;
482
483
766
    }
484
10.4k
    else {
485
10.4k
      FLAC__StreamDecoderSeekStatus status;
486
10.4k
      status = seek_callback(decoder, aspect->linkdetails[aspect->current_linknumber].end_byte,client_data);
487
10.4k
      if(status == FLAC__STREAM_DECODER_SEEK_STATUS_UNSUPPORTED)
488
0
        return FLAC__OGG_DECODER_ASPECT_READ_STATUS_CALLBACKS_NONFUNCTIONAL;
489
10.4k
      if(status == FLAC__STREAM_DECODER_SEEK_STATUS_ERROR)
490
0
        return FLAC__OGG_DECODER_ASPECT_READ_STATUS_ERROR;
491
10.4k
      FLAC__ogg_decoder_aspect_flush(aspect);
492
10.4k
      aspect->beginning_of_link = true;
493
10.4k
      aspect->need_serial_number = true;
494
10.4k
      aspect->bos_flag_seen = false;
495
10.4k
      aspect->current_linknumber++;
496
10.4k
      aspect->current_linknumber_advance_read = aspect->current_linknumber;
497
10.4k
      if(!check_size_of_link_allocation_(aspect))
498
0
        return FLAC__OGG_DECODER_ASPECT_READ_STATUS_MEMORY_ALLOCATION_ERROR;
499
10.4k
      aspect->have_working_page = false;
500
10.4k
      return FLAC__OGG_DECODER_ASPECT_READ_STATUS_OK;
501
10.4k
    }
502
11.1k
  }
503
3.72k
  else
504
3.72k
  {
505
    /* End of current link is unknown, go search for it */
506
3.72k
    const uint32_t max_page_size = 65307;
507
3.72k
    uint64_t stream_length = 0;
508
3.72k
    uint64_t current_pos = 0;
509
3.72k
    uint64_t page_pos = 0;
510
3.72k
    uint64_t target_pos = 0;
511
3.72k
    uint64_t left_pos = 0;
512
3.72k
    uint64_t right_pos = 0;
513
3.72k
    FLAC__bool did_a_seek;
514
3.72k
    FLAC__bool seek_to_left_pos = false;
515
3.72k
    FLAC__bool keep_reading = false;
516
3.72k
    FLAC__bool find_bos_twice = aspect->need_serial_number;
517
3.72k
    int ret = 0;
518
519
3.72k
    {
520
3.72k
      FLAC__StreamDecoderLengthStatus lstatus;
521
3.72k
      FLAC__StreamDecoderTellStatus tstatus;
522
523
3.72k
      lstatus = length_callback(decoder, &stream_length, client_data);
524
3.72k
      if(lstatus == FLAC__STREAM_DECODER_LENGTH_STATUS_UNSUPPORTED)
525
0
        return FLAC__OGG_DECODER_ASPECT_READ_STATUS_CALLBACKS_NONFUNCTIONAL;
526
3.72k
      if(lstatus == FLAC__STREAM_DECODER_LENGTH_STATUS_ERROR)
527
0
        return FLAC__OGG_DECODER_ASPECT_READ_STATUS_ERROR;
528
529
3.72k
      tstatus = tell_callback(decoder, &current_pos, client_data);
530
3.72k
      if(tstatus == FLAC__STREAM_DECODER_TELL_STATUS_UNSUPPORTED)
531
0
        return FLAC__OGG_DECODER_ASPECT_READ_STATUS_CALLBACKS_NONFUNCTIONAL;
532
3.72k
      if(tstatus == FLAC__STREAM_DECODER_TELL_STATUS_ERROR)
533
0
        return FLAC__OGG_DECODER_ASPECT_READ_STATUS_ERROR;
534
3.72k
    }
535
536
537
3.72k
    current_pos = current_pos - aspect->sync_state.fill + aspect->sync_state.returned;
538
3.72k
    left_pos = current_pos;
539
3.72k
    right_pos = stream_length;
540
541
118k
    while(1){
542
118k
      FLAC__bool seek_was_to_current_link = true;
543
544
118k
      if(right_pos <= left_pos || right_pos - left_pos < 9) {
545
        /* FLAC frame is at least 9 byte in size */
546
1.17k
        return FLAC__OGG_DECODER_ASPECT_READ_STATUS_ERROR;
547
1.17k
      }
548
117k
      target_pos = left_pos + (right_pos - left_pos)/2;
549
550
117k
      if(keep_reading) {
551
        /* To not end up in a loop, we need to keep reading until are able to change left_pos */
552
2.69k
        did_a_seek = false;
553
2.69k
      }
554
115k
      else if(current_pos < target_pos && current_pos + aspect->sync_state.fill - aspect->sync_state.returned > target_pos) {
555
        /* Target location is already in buffer, keep reading */
556
11.2k
        did_a_seek = false;
557
11.2k
      }
558
103k
      else if(current_pos < target_pos && current_pos + max_page_size > target_pos) {
559
        /* Target is very close to current location, just reading is probably faster than seeking */
560
36.2k
        did_a_seek = false;
561
36.2k
      }
562
67.6k
      else if(aspect->beginning_of_link) {
563
        /* Still need to save all serial numbers at start of stream, so don't seek yet */
564
65.7k
        did_a_seek = false;
565
65.7k
      }
566
1.86k
      else {
567
1.86k
        if(seek_to_left_pos || target_pos - left_pos < max_page_size) {
568
          /* Seek to start of bisect area */
569
1.35k
          target_pos = left_pos;
570
1.35k
          keep_reading = true;
571
1.35k
          seek_to_left_pos = false;
572
1.35k
        }
573
        /* Seek */
574
1.86k
        if(seek_callback(decoder, target_pos, client_data) != FLAC__STREAM_DECODER_SEEK_STATUS_OK)
575
0
          return false;
576
1.86k
        did_a_seek = true;
577
1.86k
        FLAC__ASSERT(tell_callback(decoder, &current_pos, client_data) == FLAC__STREAM_DECODER_TELL_STATUS_OK);
578
1.86k
        FLAC__ASSERT(current_pos == target_pos);
579
1.86k
        current_pos = target_pos;
580
1.86k
        (void)ogg_stream_reset(&aspect->stream_state);
581
1.86k
        (void)ogg_sync_reset(&aspect->sync_state);
582
1.86k
      }
583
584
      /* Get a page, resynchronize if necessary */
585
279k
      while((ret = ogg_sync_pageseek(&aspect->sync_state, &aspect->working_page)) <= 0 && !aspect->end_of_stream) {
586
161k
        if(ret < 0)
587
150k
          current_pos -= ret;
588
11.5k
        else {
589
          /* need more data */
590
11.5k
          FLAC__OggDecoderAspectReadStatus status = read_more_data_(aspect, read_callback, 0, decoder, client_data);
591
11.5k
          if(status != FLAC__OGG_DECODER_ASPECT_READ_STATUS_OK)
592
0
            return status;
593
11.5k
        }
594
161k
      }
595
596
117k
      page_pos = current_pos;
597
117k
      current_pos += aspect->working_page.header_len + aspect->working_page.body_len;
598
599
      /* Check whether the page serial number belongs to this link or another link */
600
117k
      if (ret > 0) {
601
115k
        if(!aspect->beginning_of_link) {
602
          /* got a page, check the serial number */
603
11.9k
          long serial_number = ogg_page_serialno(&aspect->working_page);
604
11.9k
          uint32_t i;
605
11.9k
          seek_was_to_current_link = false;
606
11.9k
          if(serial_number == aspect->linkdetails[aspect->current_linknumber].serial_number) {
607
            /* This page belongs to current link */
608
5.81k
            seek_was_to_current_link = true;
609
5.81k
          }
610
2.67M
          for(i = 0; i < aspect->linkdetails[aspect->current_linknumber].number_of_other_streams; i++) {
611
2.66M
            if(serial_number == aspect->linkdetails[aspect->current_linknumber].other_serial_numbers[i]) {
612
              /* This page belongs to the current link */
613
2.28M
              seek_was_to_current_link = true;
614
2.28M
            }
615
2.66M
          }
616
11.9k
          if(ogg_page_serialno(&aspect->working_page) == aspect->linkdetails[aspect->current_linknumber].serial_number && ogg_page_eos(&aspect->working_page)) {
617
            /* Found EOS */
618
706
            aspect->linkdetails[aspect->current_linknumber].end_byte = current_pos;
619
706
            aspect->linkdetails[aspect->current_linknumber].samples = ogg_page_granulepos(&aspect->working_page);
620
621
706
            aspect->number_of_links_indexed++;
622
706
            aspect->current_linknumber_advance_read = aspect->current_linknumber + 1;
623
706
            if(!check_size_of_link_allocation_(aspect))
624
1
              return FLAC__OGG_DECODER_ASPECT_READ_STATUS_MEMORY_ALLOCATION_ERROR;
625
626
705
            aspect->need_serial_number = true;
627
628
            /* Now, continue loop to check whether we are at end of stream or another link follows */
629
705
            FLAC__ogg_decoder_aspect_next_link(aspect);
630
705
            continue;
631
706
          }
632
11.1k
          if(seek_was_to_current_link) {
633
            /* If the seek landed on a page with the serial number of the stream we're interested in, we can be sure
634
             * the EOS page will be later in the stream. If the seek landed on a stream with a different serial number
635
             * however, we cannot be sure. It could be the EOS page of that stream has already been seen. In that case
636
             * something else needs to be done, else we could end up in an endless loop */
637
9.57k
            if(ogg_page_serialno(&aspect->working_page) == aspect->linkdetails[aspect->current_linknumber].serial_number) {
638
5.11k
              left_pos = current_pos;
639
5.11k
              keep_reading = false;
640
5.11k
            }
641
4.46k
            else {
642
4.46k
              seek_to_left_pos = true;
643
4.46k
            }
644
9.57k
          }
645
1.62k
          else if(keep_reading) {
646
            /* We read from the left_pos but found nothing interesting, so we can move left_pos up */
647
1.07k
            left_pos = current_pos;
648
1.07k
          }
649
549
          else if(did_a_seek) {
650
338
            if(right_pos <= page_pos) {
651
              /* Ended up somewhere we've already been */
652
45
              seek_to_left_pos = true;
653
45
            }
654
293
            else
655
293
              right_pos = page_pos;
656
338
          }
657
211
          else {
658
            /* Read forward but found an unknown serial number */
659
211
            return FLAC__OGG_DECODER_ASPECT_READ_STATUS_ERROR;
660
211
          }
661
11.1k
        }
662
103k
        else { /* aspect->beginning_of_link == true */
663
103k
          if(aspect->end_of_stream) {
664
6
            if(aspect->current_linknumber == 0)
665
5
              return FLAC__OGG_DECODER_ASPECT_READ_STATUS_LOST_SYNC;
666
1
            aspect->current_linknumber--;
667
1
            aspect->linkdetails[aspect->current_linknumber].is_last = true;
668
1
            return FLAC__OGG_DECODER_ASPECT_READ_STATUS_END_OF_STREAM;
669
6
          }
670
103k
          else {
671
            /* We can end up here for three reasons:
672
             * 1) We've found the end of the link and are looking whether a new one follows it. If that is the case,
673
             *    we need to finish after we found it
674
             * 2) We've just started skipping this link, and need to look for other BOS pages first. If that is the case,
675
             *    we need to continue after we found them
676
             * 3) We've don't know anything about the link that needs to be skipped yet, and we need to process the BOS
677
             *    pages first, and process the BOS pages of the next link */
678
103k
            FLAC__bool need_to_finish = aspect->need_serial_number && !find_bos_twice;
679
103k
            FLAC__OggDecoderAspectReadStatus status = process_page_(aspect, tell_callback, decoder, client_data);
680
103k
            if(status != FLAC__OGG_DECODER_ASPECT_READ_STATUS_OK)
681
51
              return status;
682
103k
            if(!aspect->need_serial_number) {
683
1.92k
              if(need_to_finish) {
684
                /* Found start of next link, we're done */
685
544
                return FLAC__OGG_DECODER_ASPECT_READ_STATUS_OK;
686
544
              }
687
1.37k
              find_bos_twice = false;
688
1.37k
            }
689
103k
            if(!aspect->beginning_of_link) {
690
              /* Done scanning BOS pages, move up left_pos */
691
1.43k
              left_pos = page_pos;
692
1.43k
            }
693
103k
          }
694
103k
        }
695
115k
      }
696
1.93k
      else if(aspect->end_of_stream) {
697
1.93k
        if(aspect->beginning_of_link && !aspect->bos_flag_seen) {
698
          /* We were looking for the next link, but found end of stream instead */
699
939
          if(aspect->current_linknumber == 0)
700
805
            return FLAC__OGG_DECODER_ASPECT_READ_STATUS_LOST_SYNC;
701
134
          aspect->current_linknumber--;
702
134
          aspect->linkdetails[aspect->current_linknumber].is_last = true;
703
134
          return FLAC__OGG_DECODER_ASPECT_READ_STATUS_END_OF_STREAM;
704
939
        }
705
995
        else if(did_a_seek) {
706
          /* Seeking to target_pos did no result in finding a page, set right_pos to that value */
707
198
          right_pos = target_pos;
708
198
        }
709
797
        else {
710
          /* We expected to find the EOS page without seeking, but ended up at the end of the stream */
711
797
          return FLAC__OGG_DECODER_ASPECT_READ_STATUS_ERROR;
712
797
        }
713
1.93k
      }
714
0
      else if(ret == 0) {
715
        /* ogg error */
716
0
        return FLAC__OGG_DECODER_ASPECT_READ_STATUS_LOST_SYNC;
717
0
      }
718
117k
    }
719
3.72k
  }
720
14.9k
}