Coverage Report

Created: 2025-08-26 06:40

/src/flac/src/libFLAC/ogg_helper.c
Line
Count
Source (jump to first uncovered line)
1
/* libFLAC - Free Lossless Audio Codec
2
 * Copyright (C) 2004-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 <stdlib.h> /* for malloc() */
38
#include <string.h> /* for memcmp(), memcpy() */
39
#include "FLAC/assert.h"
40
#include "share/alloc.h"
41
#include "private/ogg_helper.h"
42
#include "protected/stream_encoder.h"
43
44
45
static FLAC__bool full_read_(FLAC__StreamEncoder *encoder, FLAC__byte *buffer, size_t bytes, FLAC__StreamEncoderReadCallback read_callback, void *client_data)
46
0
{
47
0
  while(bytes > 0) {
48
0
    size_t bytes_read = bytes;
49
0
    switch(read_callback(encoder, buffer, &bytes_read, client_data)) {
50
0
      case FLAC__STREAM_ENCODER_READ_STATUS_CONTINUE:
51
0
        bytes -= bytes_read;
52
0
        buffer += bytes_read;
53
0
        break;
54
0
      case FLAC__STREAM_ENCODER_READ_STATUS_END_OF_STREAM:
55
0
        if(bytes_read == 0) {
56
0
          encoder->protected_->state = FLAC__STREAM_ENCODER_OGG_ERROR;
57
0
          return false;
58
0
        }
59
0
        bytes -= bytes_read;
60
0
        buffer += bytes_read;
61
0
        break;
62
0
      case FLAC__STREAM_ENCODER_READ_STATUS_ABORT:
63
0
        encoder->protected_->state = FLAC__STREAM_ENCODER_CLIENT_ERROR;
64
0
        return false;
65
0
      case FLAC__STREAM_ENCODER_READ_STATUS_UNSUPPORTED:
66
0
        return false;
67
0
      default:
68
        /* double protection: */
69
0
        FLAC__ASSERT(0);
70
0
        encoder->protected_->state = FLAC__STREAM_ENCODER_CLIENT_ERROR;
71
0
        return false;
72
0
    }
73
0
  }
74
75
0
  return true;
76
0
}
77
78
void simple_ogg_page__init(ogg_page *page)
79
0
{
80
0
  page->header = 0;
81
0
  page->header_len = 0;
82
0
  page->body = 0;
83
0
  page->body_len = 0;
84
0
}
85
86
void simple_ogg_page__clear(ogg_page *page)
87
0
{
88
0
  if(page->header)
89
0
    free(page->header);
90
0
  if(page->body)
91
0
    free(page->body);
92
0
  simple_ogg_page__init(page);
93
0
}
94
95
FLAC__bool simple_ogg_page__get_at(FLAC__StreamEncoder *encoder, FLAC__uint64 position, ogg_page *page, FLAC__StreamEncoderSeekCallback seek_callback, FLAC__StreamEncoderReadCallback read_callback, void *client_data)
96
0
{
97
0
  static const uint32_t OGG_HEADER_FIXED_PORTION_LEN = 27;
98
0
  static const uint32_t OGG_MAX_HEADER_LEN = 27/*OGG_HEADER_FIXED_PORTION_LEN*/ + 255;
99
0
  FLAC__byte crc[4];
100
0
  FLAC__StreamEncoderSeekStatus seek_status;
101
102
0
  FLAC__ASSERT(page->header == 0);
103
0
  FLAC__ASSERT(page->header_len == 0);
104
0
  FLAC__ASSERT(page->body == 0);
105
0
  FLAC__ASSERT(page->body_len == 0);
106
107
  /* move the stream pointer to the supposed beginning of the page */
108
0
  if(0 == seek_callback)
109
0
    return false;
110
0
  if((seek_status = seek_callback((FLAC__StreamEncoder*)encoder, position, client_data)) != FLAC__STREAM_ENCODER_SEEK_STATUS_OK) {
111
0
    if(seek_status == FLAC__STREAM_ENCODER_SEEK_STATUS_ERROR)
112
0
      encoder->protected_->state = FLAC__STREAM_ENCODER_CLIENT_ERROR;
113
0
    return false;
114
0
  }
115
116
  /* allocate space for the page header */
117
0
  if(0 == (page->header = safe_malloc_(OGG_MAX_HEADER_LEN))) {
118
0
    encoder->protected_->state = FLAC__STREAM_ENCODER_MEMORY_ALLOCATION_ERROR;
119
0
    return false;
120
0
  }
121
122
  /* read in the fixed part of the page header (up to but not including
123
   * the segment table */
124
0
  if(!full_read_(encoder, page->header, OGG_HEADER_FIXED_PORTION_LEN, read_callback, client_data))
125
0
    return false;
126
127
0
  page->header_len = OGG_HEADER_FIXED_PORTION_LEN + page->header[26];
128
129
  /* check to see if it's a correct, "simple" page (one packet only) */
130
0
  if(
131
0
    memcmp(page->header, "OggS", 4) ||               /* doesn't start with OggS */
132
0
    (page->header[5] & 0x01) ||                      /* continued packet */
133
0
    memcmp(page->header+6, "\0\0\0\0\0\0\0\0", 8) || /* granulepos is non-zero */
134
0
    page->header[26] == 0                            /* packet is 0-size */
135
0
  ) {
136
0
    encoder->protected_->state = FLAC__STREAM_ENCODER_OGG_ERROR;
137
0
    return false;
138
0
  }
139
140
  /* read in the segment table */
141
0
  if(!full_read_(encoder, page->header + OGG_HEADER_FIXED_PORTION_LEN, page->header[26], read_callback, client_data))
142
0
    return false;
143
144
0
  {
145
0
    uint32_t i;
146
147
    /* check to see that it specifies a single packet */
148
0
    for(i = 0; i < (uint32_t)page->header[26] - 1; i++) {
149
0
      if(page->header[i + OGG_HEADER_FIXED_PORTION_LEN] != 255) {
150
0
        encoder->protected_->state = FLAC__STREAM_ENCODER_OGG_ERROR;
151
0
        return false;
152
0
      }
153
0
    }
154
155
0
    page->body_len = 255 * i + page->header[i + OGG_HEADER_FIXED_PORTION_LEN];
156
0
  }
157
158
  /* allocate space for the page body */
159
0
  if(0 == (page->body = safe_malloc_(page->body_len))) {
160
0
    encoder->protected_->state = FLAC__STREAM_ENCODER_MEMORY_ALLOCATION_ERROR;
161
0
    return false;
162
0
  }
163
164
  /* read in the page body */
165
0
  if(!full_read_(encoder, page->body, page->body_len, read_callback, client_data))
166
0
    return false;
167
168
  /* check the CRC */
169
0
  memcpy(crc, page->header+22, 4);
170
0
  ogg_page_checksum_set(page);
171
0
  if(memcmp(crc, page->header+22, 4)) {
172
0
    encoder->protected_->state = FLAC__STREAM_ENCODER_OGG_ERROR;
173
0
    return false;
174
0
  }
175
176
0
  return true;
177
0
}
178
179
FLAC__bool simple_ogg_page__set_at(FLAC__StreamEncoder *encoder, FLAC__uint64 position, ogg_page *page, FLAC__StreamEncoderSeekCallback seek_callback, FLAC__StreamEncoderWriteCallback write_callback, void *client_data)
180
0
{
181
0
  FLAC__StreamEncoderSeekStatus seek_status;
182
183
0
  FLAC__ASSERT(page->header != 0);
184
0
  FLAC__ASSERT(page->header_len != 0);
185
0
  FLAC__ASSERT(page->body != 0);
186
0
  FLAC__ASSERT(page->body_len != 0);
187
188
  /* move the stream pointer to the supposed beginning of the page */
189
0
  if(0 == seek_callback)
190
0
    return false;
191
0
  if((seek_status = seek_callback((FLAC__StreamEncoder*)encoder, position, client_data)) != FLAC__STREAM_ENCODER_SEEK_STATUS_OK) {
192
0
    if(seek_status == FLAC__STREAM_ENCODER_SEEK_STATUS_ERROR)
193
0
      encoder->protected_->state = FLAC__STREAM_ENCODER_CLIENT_ERROR;
194
0
    return false;
195
0
  }
196
197
0
  ogg_page_checksum_set(page);
198
199
  /* re-write the page */
200
0
  if(write_callback((FLAC__StreamEncoder*)encoder, page->header, page->header_len, 0, 0, client_data) != FLAC__STREAM_ENCODER_WRITE_STATUS_OK) {
201
0
    encoder->protected_->state = FLAC__STREAM_ENCODER_CLIENT_ERROR;
202
0
    return false;
203
0
  }
204
0
  if(write_callback((FLAC__StreamEncoder*)encoder, page->body, page->body_len, 0, 0, client_data) != FLAC__STREAM_ENCODER_WRITE_STATUS_OK) {
205
0
    encoder->protected_->state = FLAC__STREAM_ENCODER_CLIENT_ERROR;
206
0
    return false;
207
0
  }
208
209
0
  return true;
210
0
}