Coverage Report

Created: 2025-10-21 06:11

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