Coverage Report

Created: 2026-06-30 06:48

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
866
{ const READ_CHUNKS * pchk = &psf->rchunks ;
43
866
  int idx ;
44
45
866
  if (marker_str)
46
866
    idx = psf_find_read_chunk_str (pchk, marker_str) ;
47
0
  else
48
0
    idx = pchk->used > 0 ? 0 : -1 ;
49
50
866
  if (idx < 0)
51
48
    return NULL ;
52
53
818
  if (psf->iterator == NULL)
54
818
  { psf->iterator = calloc (1, sizeof (SF_CHUNK_ITERATOR)) ;
55
818
    if (psf->iterator == NULL)
56
0
      return NULL ;
57
818
    } ;
58
59
818
  psf->iterator->sndfile = (SNDFILE *) psf ;
60
61
818
  if (marker_str)
62
818
  { int64_t hash ;
63
818
    size_t marker_len ;
64
818
    union
65
818
    { uint32_t marker ;
66
818
      char str [5] ;
67
818
    } u ;
68
69
818
    snprintf (u.str, sizeof (u.str), "%s", marker_str) ;
70
71
818
    marker_len = strlen (marker_str) ;
72
818
    if (marker_len > 64)
73
0
      marker_len = 64 ;
74
75
818
    hash = marker_len > 4 ? hash_of_str (marker_str) : u.marker ;
76
77
818
    memcpy (psf->iterator->id, marker_str, marker_len) ;
78
818
    psf->iterator->id_size = (unsigned) marker_len ;
79
818
    psf->iterator->hash = hash ;
80
818
    }
81
82
818
  psf->iterator->current = idx ;
83
84
818
  return psf->iterator ;
85
818
} /* psf_get_chunk_iterator */
86
87
SF_CHUNK_ITERATOR *
88
psf_next_chunk_iterator (const READ_CHUNKS * pchk , SF_CHUNK_ITERATOR * iterator)
89
1.35k
{ uint64_t hash = iterator->hash ;
90
1.35k
  uint32_t k ;
91
92
1.35k
  iterator->current++ ;
93
94
1.35k
  if (hash)
95
2.36k
  { for (k = iterator->current ; k < pchk->used ; k++)
96
1.54k
      if (pchk->chunks [k].hash == hash)
97
532
      { iterator->current = k ;
98
532
        return iterator ;
99
532
        }
100
1.35k
    }
101
0
  else if (iterator->current < pchk->used)
102
0
    return iterator ;
103
104
  /* No match, clear iterator and return NULL */
105
818
  memset (iterator, 0, sizeof (*iterator)) ;
106
818
  return NULL ;
107
1.35k
} /* psf_next_chunk_iterator */
108
109
static int
110
psf_store_read_chunk (READ_CHUNKS * pchk, const READ_CHUNK * rchunk)
111
852k
{ if (pchk->count == 0)
112
9.67k
  { pchk->used = 0 ;
113
9.67k
    pchk->count = 20 ;
114
9.67k
    pchk->chunks = calloc (pchk->count, sizeof (READ_CHUNK)) ;
115
9.67k
    if (!pchk->chunks)
116
0
    { return SFE_MALLOC_FAILED ;
117
9.67k
      } ;
118
9.67k
    }
119
843k
  else if (pchk->used > pchk->count)
120
0
    return SFE_INTERNAL ;
121
843k
  else if (pchk->used == pchk->count)
122
5.50k
  { READ_CHUNK * old_ptr = pchk->chunks ;
123
5.50k
    int new_count = 3 * (pchk->count + 1) / 2 ;
124
125
5.50k
    READ_CHUNK * new_chunks = realloc (old_ptr, new_count * sizeof (READ_CHUNK)) ;
126
5.50k
    if (new_chunks == NULL)
127
0
    {
128
0
      return SFE_MALLOC_FAILED ;
129
5.50k
      } else {
130
5.50k
      pchk->chunks = new_chunks;
131
5.50k
      } ;
132
5.50k
    pchk->count = new_count ;
133
852k
    } ;
134
135
852k
  pchk->chunks [pchk->used] = *rchunk ;
136
137
852k
  pchk->used ++ ;
138
139
852k
  return SFE_NO_ERROR ;
140
852k
} /* 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
852k
{ READ_CHUNK rchunk ;
145
146
852k
  memset (&rchunk, 0, sizeof (rchunk)) ;
147
148
852k
  rchunk.hash = marker ;
149
852k
  rchunk.mark32 = marker ;
150
852k
  rchunk.offset = offset ;
151
852k
  rchunk.len = len ;
152
153
852k
  rchunk.id_size = 4 ;
154
852k
  memcpy (rchunk.id, &marker, rchunk.id_size) ;
155
156
852k
  return psf_store_read_chunk (pchk, &rchunk) ;
157
852k
} /* psf_store_read_chunk_u32 */
158
159
int
160
psf_find_read_chunk_str (const READ_CHUNKS * pchk, const char * marker_str)
161
866
{ uint64_t hash ;
162
866
  uint32_t k ;
163
866
  union
164
866
  { uint32_t marker ;
165
866
    char str [5] ;
166
866
  } u ;
167
168
866
  snprintf (u.str, sizeof (u.str), "%s", marker_str) ;
169
170
866
  hash = strlen (marker_str) > 4 ? hash_of_str (marker_str) : u.marker ;
171
172
2.56k
  for (k = 0 ; k < pchk->used ; k++)
173
2.51k
    if (pchk->chunks [k].hash == hash)
174
818
      return k ;
175
176
48
  return -1 ;
177
866
} /* 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
1.63k
{ if (marker->current < pchk->used)
192
1.63k
    return marker->current ;
193
194
0
  return -1 ;
195
1.63k
} /* 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