Coverage Report

Created: 2026-03-08 06:21

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libsndfile/src/chunk.c
Line
Count
Source
1
/*
2
** Copyright (C) 2008-2016 Erik de Castro Lopo <erikd@mega-nerd.com>
3
** Copyright (C) 2012 IOhannes m zmoelnig, IEM <zmoelnig@iem.at>
4
**
5
** This program is free software; you can redistribute it and/or modify
6
** it under the terms of the GNU Lesser General Public License as published by
7
** the Free Software Foundation; either version 2.1 of the License, or
8
** (at your option) any later version.
9
**
10
** This program is distributed in the hope that it will be useful,
11
** but WITHOUT ANY WARRANTY; without even the implied warranty of
12
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
** GNU Lesser General Public License for more details.
14
**
15
** You should have received a copy of the GNU Lesser General Public License
16
** along with this program; if not, write to the Free Software
17
** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
*/
19
20
#include  "sfconfig.h"
21
22
#include  <stdlib.h>
23
#include  <string.h>
24
25
#include  "sndfile.h"
26
#include  "sfendian.h"
27
#include  "common.h"
28
29
static int64_t
30
hash_of_str (const char * str)
31
0
{ int64_t marker = 0 ;
32
0
  int k ;
33
34
0
  for (k = 0 ; str [k] ; k++)
35
0
    marker = marker * 0x7f + ((const uint8_t *) str) [k] ;
36
37
0
  return marker ;
38
0
} /* hash_of_str */
39
40
SF_CHUNK_ITERATOR *
41
psf_get_chunk_iterator (SF_PRIVATE * psf, const char * marker_str)
42
1.97k
{ const READ_CHUNKS * pchk = &psf->rchunks ;
43
1.97k
  int idx ;
44
45
1.97k
  if (marker_str)
46
1.97k
    idx = psf_find_read_chunk_str (pchk, marker_str) ;
47
0
  else
48
0
    idx = pchk->used > 0 ? 0 : -1 ;
49
50
1.97k
  if (idx < 0)
51
131
    return NULL ;
52
53
1.84k
  if (psf->iterator == NULL)
54
1.84k
  { psf->iterator = calloc (1, sizeof (SF_CHUNK_ITERATOR)) ;
55
1.84k
    if (psf->iterator == NULL)
56
0
      return NULL ;
57
1.84k
    } ;
58
59
1.84k
  psf->iterator->sndfile = (SNDFILE *) psf ;
60
61
1.84k
  if (marker_str)
62
1.84k
  { int64_t hash ;
63
1.84k
    size_t marker_len ;
64
1.84k
    union
65
1.84k
    { uint32_t marker ;
66
1.84k
      char str [5] ;
67
1.84k
    } u ;
68
69
1.84k
    snprintf (u.str, sizeof (u.str), "%s", marker_str) ;
70
71
1.84k
    marker_len = strlen (marker_str) ;
72
1.84k
    if (marker_len > 64)
73
0
      marker_len = 64 ;
74
75
1.84k
    hash = marker_len > 4 ? hash_of_str (marker_str) : u.marker ;
76
77
1.84k
    memcpy (psf->iterator->id, marker_str, marker_len) ;
78
1.84k
    psf->iterator->id_size = (unsigned) marker_len ;
79
1.84k
    psf->iterator->hash = hash ;
80
1.84k
    }
81
82
1.84k
  psf->iterator->current = idx ;
83
84
1.84k
  return psf->iterator ;
85
1.84k
} /* psf_get_chunk_iterator */
86
87
SF_CHUNK_ITERATOR *
88
psf_next_chunk_iterator (const READ_CHUNKS * pchk , SF_CHUNK_ITERATOR * iterator)
89
3.51k
{ uint64_t hash = iterator->hash ;
90
3.51k
  uint32_t k ;
91
92
3.51k
  iterator->current++ ;
93
94
3.51k
  if (hash)
95
6.00k
  { for (k = iterator->current ; k < pchk->used ; k++)
96
4.16k
      if (pchk->chunks [k].hash == hash)
97
1.67k
      { iterator->current = k ;
98
1.67k
        return iterator ;
99
1.67k
        }
100
3.51k
    }
101
0
  else if (iterator->current < pchk->used)
102
0
    return iterator ;
103
104
  /* No match, clear iterator and return NULL */
105
1.84k
  memset (iterator, 0, sizeof (*iterator)) ;
106
1.84k
  return NULL ;
107
3.51k
} /* psf_next_chunk_iterator */
108
109
static int
110
psf_store_read_chunk (READ_CHUNKS * pchk, const READ_CHUNK * rchunk)
111
1.86M
{ if (pchk->count == 0)
112
22.7k
  { pchk->used = 0 ;
113
22.7k
    pchk->count = 20 ;
114
22.7k
    pchk->chunks = calloc (pchk->count, sizeof (READ_CHUNK)) ;
115
22.7k
    if (!pchk->chunks)
116
0
    { return SFE_MALLOC_FAILED ;
117
22.7k
      } ;
118
22.7k
    }
119
1.83M
  else if (pchk->used > pchk->count)
120
0
    return SFE_INTERNAL ;
121
1.83M
  else if (pchk->used == pchk->count)
122
12.1k
  { READ_CHUNK * old_ptr = pchk->chunks ;
123
12.1k
    int new_count = 3 * (pchk->count + 1) / 2 ;
124
125
12.1k
    READ_CHUNK * new_chunks = realloc (old_ptr, new_count * sizeof (READ_CHUNK)) ;
126
12.1k
    if (new_chunks == NULL)
127
0
    {
128
0
      return SFE_MALLOC_FAILED ;
129
12.1k
      } else {
130
12.1k
      pchk->chunks = new_chunks;
131
12.1k
      } ;
132
12.1k
    pchk->count = new_count ;
133
1.86M
    } ;
134
135
1.86M
  pchk->chunks [pchk->used] = *rchunk ;
136
137
1.86M
  pchk->used ++ ;
138
139
1.86M
  return SFE_NO_ERROR ;
140
1.86M
} /* psf_store_read_chunk */
141
142
int
143
psf_store_read_chunk_u32 (READ_CHUNKS * pchk, uint32_t marker, sf_count_t offset, uint32_t len)
144
1.86M
{ READ_CHUNK rchunk ;
145
146
1.86M
  memset (&rchunk, 0, sizeof (rchunk)) ;
147
148
1.86M
  rchunk.hash = marker ;
149
1.86M
  rchunk.mark32 = marker ;
150
1.86M
  rchunk.offset = offset ;
151
1.86M
  rchunk.len = len ;
152
153
1.86M
  rchunk.id_size = 4 ;
154
1.86M
  memcpy (rchunk.id, &marker, rchunk.id_size) ;
155
156
1.86M
  return psf_store_read_chunk (pchk, &rchunk) ;
157
1.86M
} /* psf_store_read_chunk_u32 */
158
159
int
160
psf_find_read_chunk_str (const READ_CHUNKS * pchk, const char * marker_str)
161
1.97k
{ uint64_t hash ;
162
1.97k
  uint32_t k ;
163
1.97k
  union
164
1.97k
  { uint32_t marker ;
165
1.97k
    char str [5] ;
166
1.97k
  } u ;
167
168
1.97k
  snprintf (u.str, sizeof (u.str), "%s", marker_str) ;
169
170
1.97k
  hash = strlen (marker_str) > 4 ? hash_of_str (marker_str) : u.marker ;
171
172
5.51k
  for (k = 0 ; k < pchk->used ; k++)
173
5.38k
    if (pchk->chunks [k].hash == hash)
174
1.84k
      return k ;
175
176
131
  return -1 ;
177
1.97k
} /* psf_find_read_chunk_str */
178
179
int
180
psf_find_read_chunk_m32 (const READ_CHUNKS * pchk, uint32_t marker)
181
0
{ uint32_t k ;
182
183
0
  for (k = 0 ; k < pchk->used ; k++)
184
0
    if (pchk->chunks [k].mark32 == marker)
185
0
      return k ;
186
187
0
  return -1 ;
188
0
} /* psf_find_read_chunk_m32 */
189
int
190
psf_find_read_chunk_iterator (const READ_CHUNKS * pchk, const SF_CHUNK_ITERATOR * marker)
191
3.68k
{ if (marker->current < pchk->used)
192
3.68k
    return marker->current ;
193
194
0
  return -1 ;
195
3.68k
} /* psf_find_read_chunk_iterator */
196
197
int
198
psf_store_read_chunk_str (READ_CHUNKS * pchk, const char * marker_str, sf_count_t offset, uint32_t len)
199
0
{ READ_CHUNK rchunk ;
200
0
  union
201
0
  { uint32_t marker ;
202
0
    char str [5] ;
203
0
  } u ;
204
0
  size_t marker_len ;
205
206
0
  memset (&rchunk, 0, sizeof (rchunk)) ;
207
0
  snprintf (u.str, sizeof (u.str), "%s", marker_str) ;
208
209
0
  marker_len = strlen (marker_str) ;
210
211
0
  rchunk.hash = marker_len > 4 ? hash_of_str (marker_str) : u.marker ;
212
0
  rchunk.mark32 = u.marker ;
213
0
  rchunk.offset = offset ;
214
0
  rchunk.len = len ;
215
216
0
  rchunk.id_size = marker_len > 64 ? 64 : (unsigned) marker_len ;
217
0
  memcpy (rchunk.id, marker_str, rchunk.id_size) ;
218
219
0
  return psf_store_read_chunk (pchk, &rchunk) ;
220
0
} /* psf_store_read_chunk_str */
221
222
int
223
psf_save_write_chunk (WRITE_CHUNKS * pchk, const SF_CHUNK_INFO * chunk_info)
224
0
{ union
225
0
  { uint32_t marker ;
226
0
    char str [5] ;
227
    /* Update snprintf() format string below when changing this */
228
0
  } u ;
229
0
  uint32_t len ;
230
231
0
  if (pchk->count == 0)
232
0
  { pchk->used = 0 ;
233
0
    pchk->count = 20 ;
234
0
    pchk->chunks = calloc (pchk->count, sizeof (WRITE_CHUNK)) ;
235
0
    if (!pchk->chunks)
236
0
    { return SFE_MALLOC_FAILED ;
237
0
      } ;
238
0
    }
239
0
  else if (pchk->used >= pchk->count)
240
0
  { WRITE_CHUNK * old_ptr = pchk->chunks ;
241
0
    int new_count = 3 * (pchk->count + 1) / 2 ;
242
243
0
    WRITE_CHUNK * new_chunks = realloc (old_ptr, new_count * sizeof (WRITE_CHUNK)) ;
244
0
    if (new_chunks == NULL)
245
0
    {
246
0
      return SFE_MALLOC_FAILED ;
247
0
      } else {
248
0
      pchk->chunks = new_chunks;
249
0
      } ;
250
0
    } ;
251
252
0
  len = chunk_info->datalen ;
253
0
  while (len & 3) len ++ ;
254
255
0
  snprintf (u.str, sizeof (u.str), "%.4s", chunk_info->id) ;
256
257
0
  pchk->chunks [pchk->used].hash = strlen (chunk_info->id) > 4 ? hash_of_str (chunk_info->id) : u.marker ;
258
0
  pchk->chunks [pchk->used].mark32 = u.marker ;
259
0
  pchk->chunks [pchk->used].len = len ;
260
0
  pchk->chunks [pchk->used].data = psf_memdup (chunk_info->data, chunk_info->datalen) ;
261
262
0
  pchk->used ++ ;
263
264
0
  return SFE_NO_ERROR ;
265
0
} /* psf_save_write_chunk */
266