/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 | | |