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
hash_of_str(const char * str)30 hash_of_str (const char * str)
31 { int64_t marker = 0 ;
32 int k ;
33
34 for (k = 0 ; str [k] ; k++)
35 marker = marker * 0x7f + ((const uint8_t *) str) [k] ;
36
37 return marker ;
38 } /* hash_of_str */
39
40 SF_CHUNK_ITERATOR *
psf_get_chunk_iterator(SF_PRIVATE * psf,const char * marker_str)41 psf_get_chunk_iterator (SF_PRIVATE * psf, const char * marker_str)
42 { const READ_CHUNKS * pchk = &psf->rchunks ;
43 int idx ;
44
45 if (marker_str)
46 idx = psf_find_read_chunk_str (pchk, marker_str) ;
47 else
48 idx = pchk->used > 0 ? 0 : -1 ;
49
50 if (idx < 0)
51 return NULL ;
52
53 if (psf->iterator == NULL)
54 { psf->iterator = calloc (1, sizeof (SF_CHUNK_ITERATOR)) ;
55 if (psf->iterator == NULL)
56 return NULL ;
57 } ;
58
59 psf->iterator->sndfile = (SNDFILE *) psf ;
60
61 if (marker_str)
62 { int64_t hash ;
63 size_t marker_len ;
64 union
65 { uint32_t marker ;
66 char str [5] ;
67 } u ;
68
69 snprintf (u.str, sizeof (u.str), "%s", marker_str) ;
70
71 marker_len = strlen (marker_str) ;
72 if (marker_len > 64)
73 marker_len = 64 ;
74
75 hash = marker_len > 4 ? hash_of_str (marker_str) : u.marker ;
76
77 memcpy (psf->iterator->id, marker_str, marker_len) ;
78 psf->iterator->id_size = marker_len ;
79 psf->iterator->hash = hash ;
80 }
81
82 psf->iterator->current = idx ;
83
84 return psf->iterator ;
85 } /* psf_get_chunk_iterator */
86
87 SF_CHUNK_ITERATOR *
psf_next_chunk_iterator(const READ_CHUNKS * pchk,SF_CHUNK_ITERATOR * iterator)88 psf_next_chunk_iterator (const READ_CHUNKS * pchk , SF_CHUNK_ITERATOR * iterator)
89 { uint64_t hash = iterator->hash ;
90 uint32_t k ;
91
92 iterator->current++ ;
93
94 if (hash)
95 { for (k = iterator->current ; k < pchk->used ; k++)
96 if (pchk->chunks [k].hash == hash)
97 { iterator->current = k ;
98 return iterator ;
99 }
100 }
101 else if (iterator->current < pchk->used)
102 return iterator ;
103
104 /* No match, clear iterator and return NULL */
105 memset (iterator, 0, sizeof (*iterator)) ;
106 return NULL ;
107 } /* psf_next_chunk_iterator */
108
109 static int
psf_store_read_chunk(READ_CHUNKS * pchk,const READ_CHUNK * rchunk)110 psf_store_read_chunk (READ_CHUNKS * pchk, const READ_CHUNK * rchunk)
111 { if (pchk->count == 0)
112 { pchk->used = 0 ;
113 pchk->count = 20 ;
114 pchk->chunks = calloc (pchk->count, sizeof (READ_CHUNK)) ;
115 }
116 else if (pchk->used > pchk->count)
117 return SFE_INTERNAL ;
118 else if (pchk->used == pchk->count)
119 { READ_CHUNK * old_ptr = pchk->chunks ;
120 int new_count = 3 * (pchk->count + 1) / 2 ;
121
122 pchk->chunks = realloc (old_ptr, new_count * sizeof (READ_CHUNK)) ;
123 if (pchk->chunks == NULL)
124 { pchk->chunks = old_ptr ;
125 return SFE_MALLOC_FAILED ;
126 } ;
127 pchk->count = new_count ;
128 } ;
129
130 pchk->chunks [pchk->used] = *rchunk ;
131
132 pchk->used ++ ;
133
134 return SFE_NO_ERROR ;
135 } /* psf_store_read_chunk */
136
137 int
psf_store_read_chunk_u32(READ_CHUNKS * pchk,uint32_t marker,sf_count_t offset,uint32_t len)138 psf_store_read_chunk_u32 (READ_CHUNKS * pchk, uint32_t marker, sf_count_t offset, uint32_t len)
139 { READ_CHUNK rchunk ;
140
141 memset (&rchunk, 0, sizeof (rchunk)) ;
142
143 rchunk.hash = marker ;
144 rchunk.mark32 = marker ;
145 rchunk.offset = offset ;
146 rchunk.len = len ;
147
148 rchunk.id_size = 4 ;
149 memcpy (rchunk.id, &marker, rchunk.id_size) ;
150
151 return psf_store_read_chunk (pchk, &rchunk) ;
152 } /* psf_store_read_chunk_u32 */
153
154 int
psf_find_read_chunk_str(const READ_CHUNKS * pchk,const char * marker_str)155 psf_find_read_chunk_str (const READ_CHUNKS * pchk, const char * marker_str)
156 { uint64_t hash ;
157 uint32_t k ;
158 union
159 { uint32_t marker ;
160 char str [5] ;
161 } u ;
162
163 snprintf (u.str, sizeof (u.str), "%s", marker_str) ;
164
165 hash = strlen (marker_str) > 4 ? hash_of_str (marker_str) : u.marker ;
166
167 for (k = 0 ; k < pchk->used ; k++)
168 if (pchk->chunks [k].hash == hash)
169 return k ;
170
171 return -1 ;
172 } /* psf_find_read_chunk_str */
173
174 int
psf_find_read_chunk_m32(const READ_CHUNKS * pchk,uint32_t marker)175 psf_find_read_chunk_m32 (const READ_CHUNKS * pchk, uint32_t marker)
176 { uint32_t k ;
177
178 for (k = 0 ; k < pchk->used ; k++)
179 if (pchk->chunks [k].mark32 == marker)
180 return k ;
181
182 return -1 ;
183 } /* psf_find_read_chunk_m32 */
184 int
psf_find_read_chunk_iterator(const READ_CHUNKS * pchk,const SF_CHUNK_ITERATOR * marker)185 psf_find_read_chunk_iterator (const READ_CHUNKS * pchk, const SF_CHUNK_ITERATOR * marker)
186 { if (marker->current < pchk->used)
187 return marker->current ;
188
189 return -1 ;
190 } /* psf_find_read_chunk_iterator */
191
192 int
psf_store_read_chunk_str(READ_CHUNKS * pchk,const char * marker_str,sf_count_t offset,uint32_t len)193 psf_store_read_chunk_str (READ_CHUNKS * pchk, const char * marker_str, sf_count_t offset, uint32_t len)
194 { READ_CHUNK rchunk ;
195 union
196 { uint32_t marker ;
197 char str [5] ;
198 } u ;
199 size_t marker_len ;
200
201 memset (&rchunk, 0, sizeof (rchunk)) ;
202 snprintf (u.str, sizeof (u.str), "%s", marker_str) ;
203
204 marker_len = strlen (marker_str) ;
205
206 rchunk.hash = marker_len > 4 ? hash_of_str (marker_str) : u.marker ;
207 rchunk.mark32 = u.marker ;
208 rchunk.offset = offset ;
209 rchunk.len = len ;
210
211 rchunk.id_size = marker_len > 64 ? 64 : marker_len ;
212 memcpy (rchunk.id, marker_str, rchunk.id_size) ;
213
214 return psf_store_read_chunk (pchk, &rchunk) ;
215 } /* psf_store_read_chunk_str */
216
217 int
psf_save_write_chunk(WRITE_CHUNKS * pchk,const SF_CHUNK_INFO * chunk_info)218 psf_save_write_chunk (WRITE_CHUNKS * pchk, const SF_CHUNK_INFO * chunk_info)
219 { union
220 { uint32_t marker ;
221 char str [5] ;
222 /* Update snprintf() format string below when changing this */
223 } u ;
224 uint32_t len ;
225
226 if (pchk->count == 0)
227 { pchk->used = 0 ;
228 pchk->count = 20 ;
229 pchk->chunks = calloc (pchk->count, sizeof (WRITE_CHUNK)) ;
230 }
231 else if (pchk->used >= pchk->count)
232 { WRITE_CHUNK * old_ptr = pchk->chunks ;
233 int new_count = 3 * (pchk->count + 1) / 2 ;
234
235 pchk->chunks = realloc (old_ptr, new_count * sizeof (WRITE_CHUNK)) ;
236 if (pchk->chunks == NULL)
237 { pchk->chunks = old_ptr ;
238 return SFE_MALLOC_FAILED ;
239 } ;
240 } ;
241
242 len = chunk_info->datalen ;
243 while (len & 3) len ++ ;
244
245 snprintf (u.str, sizeof (u.str), "%.4s", chunk_info->id) ;
246
247 pchk->chunks [pchk->used].hash = strlen (chunk_info->id) > 4 ? hash_of_str (chunk_info->id) : u.marker ;
248 pchk->chunks [pchk->used].mark32 = u.marker ;
249 pchk->chunks [pchk->used].len = len ;
250 pchk->chunks [pchk->used].data = psf_memdup (chunk_info->data, chunk_info->datalen) ;
251
252 pchk->used ++ ;
253
254 return SFE_NO_ERROR ;
255 } /* psf_save_write_chunk */
256
257