• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 = (unsigned) 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 		if (!pchk->chunks)
116 		{	return SFE_MALLOC_FAILED ;
117 			} ;
118 		}
119 	else if (pchk->used > pchk->count)
120 		return SFE_INTERNAL ;
121 	else if (pchk->used == pchk->count)
122 	{	READ_CHUNK * old_ptr = pchk->chunks ;
123 		int new_count = 3 * (pchk->count + 1) / 2 ;
124 
125 		pchk->chunks = realloc (old_ptr, new_count * sizeof (READ_CHUNK)) ;
126 		if (pchk->chunks == NULL)
127 		{	pchk->chunks = old_ptr ;
128 			return SFE_MALLOC_FAILED ;
129 			} ;
130 		pchk->count = new_count ;
131 		} ;
132 
133 	pchk->chunks [pchk->used] = *rchunk ;
134 
135 	pchk->used ++ ;
136 
137 	return SFE_NO_ERROR ;
138 } /* psf_store_read_chunk */
139 
140 int
psf_store_read_chunk_u32(READ_CHUNKS * pchk,uint32_t marker,sf_count_t offset,uint32_t len)141 psf_store_read_chunk_u32 (READ_CHUNKS * pchk, uint32_t marker, sf_count_t offset, uint32_t len)
142 {	READ_CHUNK rchunk ;
143 
144 	memset (&rchunk, 0, sizeof (rchunk)) ;
145 
146 	rchunk.hash = marker ;
147 	rchunk.mark32 = marker ;
148 	rchunk.offset = offset ;
149 	rchunk.len = len ;
150 
151 	rchunk.id_size = 4 ;
152 	memcpy (rchunk.id, &marker, rchunk.id_size) ;
153 
154 	return psf_store_read_chunk (pchk, &rchunk) ;
155 } /* psf_store_read_chunk_u32 */
156 
157 int
psf_find_read_chunk_str(const READ_CHUNKS * pchk,const char * marker_str)158 psf_find_read_chunk_str (const READ_CHUNKS * pchk, const char * marker_str)
159 {	uint64_t hash ;
160 	uint32_t k ;
161 	union
162 	{	uint32_t marker ;
163 		char str [5] ;
164 	} u ;
165 
166 	snprintf (u.str, sizeof (u.str), "%s", marker_str) ;
167 
168 	hash = strlen (marker_str) > 4 ? hash_of_str (marker_str) : u.marker ;
169 
170 	for (k = 0 ; k < pchk->used ; k++)
171 		if (pchk->chunks [k].hash == hash)
172 			return k ;
173 
174 	return -1 ;
175 } /* psf_find_read_chunk_str */
176 
177 int
psf_find_read_chunk_m32(const READ_CHUNKS * pchk,uint32_t marker)178 psf_find_read_chunk_m32 (const READ_CHUNKS * pchk, uint32_t marker)
179 {	uint32_t k ;
180 
181 	for (k = 0 ; k < pchk->used ; k++)
182 		if (pchk->chunks [k].mark32 == marker)
183 			return k ;
184 
185 	return -1 ;
186 } /* psf_find_read_chunk_m32 */
187 int
psf_find_read_chunk_iterator(const READ_CHUNKS * pchk,const SF_CHUNK_ITERATOR * marker)188 psf_find_read_chunk_iterator (const READ_CHUNKS * pchk, const SF_CHUNK_ITERATOR * marker)
189 {	if (marker->current < pchk->used)
190 		return marker->current ;
191 
192 	return -1 ;
193 } /* psf_find_read_chunk_iterator */
194 
195 int
psf_store_read_chunk_str(READ_CHUNKS * pchk,const char * marker_str,sf_count_t offset,uint32_t len)196 psf_store_read_chunk_str (READ_CHUNKS * pchk, const char * marker_str, sf_count_t offset, uint32_t len)
197 {	READ_CHUNK rchunk ;
198 	union
199 	{	uint32_t marker ;
200 		char str [5] ;
201 	} u ;
202 	size_t marker_len ;
203 
204 	memset (&rchunk, 0, sizeof (rchunk)) ;
205 	snprintf (u.str, sizeof (u.str), "%s", marker_str) ;
206 
207 	marker_len = strlen (marker_str) ;
208 
209 	rchunk.hash = marker_len > 4 ? hash_of_str (marker_str) : u.marker ;
210 	rchunk.mark32 = u.marker ;
211 	rchunk.offset = offset ;
212 	rchunk.len = len ;
213 
214 	rchunk.id_size = marker_len > 64 ? 64 : (unsigned) marker_len ;
215 	memcpy (rchunk.id, marker_str, rchunk.id_size) ;
216 
217 	return psf_store_read_chunk (pchk, &rchunk) ;
218 } /* psf_store_read_chunk_str */
219 
220 int
psf_save_write_chunk(WRITE_CHUNKS * pchk,const SF_CHUNK_INFO * chunk_info)221 psf_save_write_chunk (WRITE_CHUNKS * pchk, const SF_CHUNK_INFO * chunk_info)
222 {	union
223 	{	uint32_t marker ;
224 		char str [5] ;
225 		/* Update snprintf() format string below when changing this */
226 	} u ;
227 	uint32_t len ;
228 
229 	if (pchk->count == 0)
230 	{	pchk->used = 0 ;
231 		pchk->count = 20 ;
232 		pchk->chunks = calloc (pchk->count, sizeof (WRITE_CHUNK)) ;
233 		if (!pchk->chunks)
234 		{	return SFE_MALLOC_FAILED ;
235 			} ;
236 		}
237 	else if (pchk->used >= pchk->count)
238 	{	WRITE_CHUNK * old_ptr = pchk->chunks ;
239 		int new_count = 3 * (pchk->count + 1) / 2 ;
240 
241 		pchk->chunks = realloc (old_ptr, new_count * sizeof (WRITE_CHUNK)) ;
242 		if (pchk->chunks == NULL)
243 		{	pchk->chunks = old_ptr ;
244 			return SFE_MALLOC_FAILED ;
245 			} ;
246 		} ;
247 
248 	len = chunk_info->datalen ;
249 	while (len & 3) len ++ ;
250 
251 	snprintf (u.str, sizeof (u.str), "%.4s", chunk_info->id) ;
252 
253 	pchk->chunks [pchk->used].hash = strlen (chunk_info->id) > 4 ? hash_of_str (chunk_info->id) : u.marker ;
254 	pchk->chunks [pchk->used].mark32 = u.marker ;
255 	pchk->chunks [pchk->used].len = len ;
256 	pchk->chunks [pchk->used].data = psf_memdup (chunk_info->data, chunk_info->datalen) ;
257 
258 	pchk->used ++ ;
259 
260 	return SFE_NO_ERROR ;
261 } /* psf_save_write_chunk */
262 
263