• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2 ** Copyright (C) 1999-2017 Erik de Castro Lopo <erikd@mega-nerd.com>
3 **
4 ** This program is free software; you can redistribute it and/or modify
5 ** it under the terms of the GNU Lesser General Public License as published by
6 ** the Free Software Foundation; either version 2.1 of the License, or
7 ** (at your option) any later version.
8 **
9 ** This program is distributed in the hope that it will be useful,
10 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
11 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 ** GNU Lesser General Public License for more details.
13 **
14 ** You should have received a copy of the GNU Lesser General Public License
15 ** along with this program; if not, write to the Free Software
16 ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17 */
18 
19 #include "sfconfig.h"
20 
21 #include <stdio.h>
22 #include <string.h>
23 #include <ctype.h>
24 #include <stdarg.h>
25 
26 #include "sndfile.h"
27 #include "sfendian.h"
28 #include "common.h"
29 
30 
31 /*------------------------------------------------------------------------------
32  * Macros to handle big/little endian issues.
33 */
34 
35 #define FORM_MARKER	(MAKE_MARKER ('F', 'O', 'R', 'M'))
36 #define SVX8_MARKER	(MAKE_MARKER ('8', 'S', 'V', 'X'))
37 #define SV16_MARKER	(MAKE_MARKER ('1', '6', 'S', 'V'))
38 #define VHDR_MARKER	(MAKE_MARKER ('V', 'H', 'D', 'R'))
39 #define BODY_MARKER	(MAKE_MARKER ('B', 'O', 'D', 'Y'))
40 
41 #define ATAK_MARKER	(MAKE_MARKER ('A', 'T', 'A', 'K'))
42 #define RLSE_MARKER	(MAKE_MARKER ('R', 'L', 'S', 'E'))
43 
44 #define c_MARKER	(MAKE_MARKER ('(', 'c', ')', ' '))
45 #define NAME_MARKER	(MAKE_MARKER ('N', 'A', 'M', 'E'))
46 #define AUTH_MARKER	(MAKE_MARKER ('A', 'U', 'T', 'H'))
47 #define ANNO_MARKER	(MAKE_MARKER ('A', 'N', 'N', 'O'))
48 #define CHAN_MARKER	(MAKE_MARKER ('C', 'H', 'A', 'N'))
49 
50 /*------------------------------------------------------------------------------
51  * Typedefs for file chunks.
52 */
53 
54 typedef struct
55 {	unsigned int	oneShotHiSamples, repeatHiSamples, samplesPerHiCycle ;
56 	unsigned short	samplesPerSec ;
57 	unsigned char	octave, compression ;
58 	unsigned int	volume ;
59 } VHDR_CHUNK ;
60 
61 enum {
62 	HAVE_FORM	= 0x01,
63 
64 	HAVE_SVX	= 0x02,
65 	HAVE_VHDR	= 0x04,
66 	HAVE_BODY	= 0x08
67 } ;
68 
69 /*------------------------------------------------------------------------------
70  * Private static functions.
71 */
72 
73 static int	svx_close	(SF_PRIVATE *psf) ;
74 static int	svx_write_header (SF_PRIVATE *psf, int calc_length) ;
75 static int 	svx_read_header	(SF_PRIVATE *psf) ;
76 
77 /*------------------------------------------------------------------------------
78 ** Public function.
79 */
80 
81 int
svx_open(SF_PRIVATE * psf)82 svx_open	(SF_PRIVATE *psf)
83 {	int error ;
84 
85 	if (psf->file.mode == SFM_READ || (psf->file.mode == SFM_RDWR && psf->filelength > 0))
86 	{	if ((error = svx_read_header (psf)))
87 			return error ;
88 
89 		psf->endian = SF_ENDIAN_BIG ;			/* All SVX files are big endian. */
90 
91 		psf->blockwidth = psf->sf.channels * psf->bytewidth ;
92 		if (psf->blockwidth)
93 			psf->sf.frames = psf->datalength / psf->blockwidth ;
94 
95 		psf_fseek (psf, psf->dataoffset, SEEK_SET) ;
96 		} ;
97 
98 	if (psf->file.mode == SFM_WRITE || psf->file.mode == SFM_RDWR)
99 	{	if (psf->is_pipe)
100 			return SFE_NO_PIPE_WRITE ;
101 
102 		if ((SF_CONTAINER (psf->sf.format)) != SF_FORMAT_SVX)
103 			return	SFE_BAD_OPEN_FORMAT ;
104 
105 		psf->endian = SF_ENDIAN (psf->sf.format) ;
106 
107 		if (psf->endian == SF_ENDIAN_LITTLE || (CPU_IS_LITTLE_ENDIAN && psf->endian == SF_ENDIAN_CPU))
108 			return SFE_BAD_ENDIAN ;
109 
110 		psf->endian = SF_ENDIAN_BIG ;			/* All SVX files are big endian. */
111 
112 		error = svx_write_header (psf, SF_FALSE) ;
113 		if (error)
114 			return error ;
115 
116 		psf->write_header = svx_write_header ;
117 		} ;
118 
119 	psf->container_close = svx_close ;
120 
121 	if ((error = pcm_init (psf)))
122 		return error ;
123 
124 	return 0 ;
125 } /* svx_open */
126 
127 /*------------------------------------------------------------------------------
128 */
129 
130 static int
svx_read_header(SF_PRIVATE * psf)131 svx_read_header	(SF_PRIVATE *psf)
132 {	VHDR_CHUNK		vhdr ;
133 	uint32_t		chunk_size, marker ;
134 	int				filetype = 0, parsestage = 0, done = 0 ;
135 	int 			bytecount = 0, channels ;
136 
137 	if (psf->filelength > SF_PLATFORM_S64 (0xffffffff))
138 		psf_log_printf (psf, "Warning : filelength > 0xffffffff. This is bad!!!!\n") ;
139 
140 	memset (&vhdr, 0, sizeof (vhdr)) ;
141 	psf_binheader_readf (psf, "p", 0) ;
142 
143 	/* Set default number of channels. Modify later if necessary */
144 	psf->sf.channels = 1 ;
145 
146 	psf->sf.format = SF_FORMAT_SVX ;
147 
148 	while (! done)
149 	{	psf_binheader_readf (psf, "Em4", &marker, &chunk_size) ;
150 
151 		switch (marker)
152 		{	case FORM_MARKER :
153 					if (parsestage)
154 						return SFE_SVX_NO_FORM ;
155 
156 					if (chunk_size != psf->filelength - 2 * sizeof (chunk_size))
157 						psf_log_printf (psf, "FORM : %u (should be %u)\n", chunk_size, (uint32_t) psf->filelength - 2 * sizeof (chunk_size)) ;
158 					else
159 						psf_log_printf (psf, "FORM : %u\n", chunk_size) ;
160 					parsestage |= HAVE_FORM ;
161 
162 					psf_binheader_readf (psf, "m", &marker) ;
163 
164 					filetype = marker ;
165 					psf_log_printf (psf, " %M\n", marker) ;
166 					parsestage |= HAVE_SVX ;
167 					break ;
168 
169 			case VHDR_MARKER :
170 					if (! (parsestage & (HAVE_FORM | HAVE_SVX)))
171 						return SFE_SVX_NO_FORM ;
172 
173 					psf_log_printf (psf, " VHDR : %d\n", chunk_size) ;
174 
175 					psf_binheader_readf (psf, "E4442114", &(vhdr.oneShotHiSamples), &(vhdr.repeatHiSamples),
176 						&(vhdr.samplesPerHiCycle), &(vhdr.samplesPerSec), &(vhdr.octave), &(vhdr.compression),
177 						&(vhdr.volume)) ;
178 
179 					psf_log_printf (psf, "  OneShotHiSamples  : %d\n", vhdr.oneShotHiSamples) ;
180 					psf_log_printf (psf, "  RepeatHiSamples   : %d\n", vhdr.repeatHiSamples) ;
181 					psf_log_printf (psf, "  samplesPerHiCycle : %d\n", vhdr.samplesPerHiCycle) ;
182 					psf_log_printf (psf, "  Sample Rate       : %d\n", vhdr.samplesPerSec) ;
183 					psf_log_printf (psf, "  Octave            : %d\n", vhdr.octave) ;
184 
185 					psf_log_printf (psf, "  Compression       : %d => ", vhdr.compression) ;
186 
187 					switch (vhdr.compression)
188 					{	case 0 : psf_log_printf (psf, "None.\n") ;
189 								break ;
190 						case 1 : psf_log_printf (psf, "Fibonacci delta\n") ;
191 								break ;
192 						case 2 : psf_log_printf (psf, "Exponential delta\n") ;
193 								break ;
194 						} ;
195 
196 					psf_log_printf (psf, "  Volume            : %d\n", vhdr.volume) ;
197 
198 					psf->sf.samplerate 	= vhdr.samplesPerSec ;
199 
200 					if (filetype == SVX8_MARKER)
201 					{	psf->sf.format |= SF_FORMAT_PCM_S8 ;
202 						psf->bytewidth = 1 ;
203 						}
204 					else if (filetype == SV16_MARKER)
205 					{	psf->sf.format |= SF_FORMAT_PCM_16 ;
206 						psf->bytewidth = 2 ;
207 						} ;
208 
209 					parsestage |= HAVE_VHDR ;
210 					break ;
211 
212 			case BODY_MARKER :
213 					if (! (parsestage & HAVE_VHDR))
214 						return SFE_SVX_NO_BODY ;
215 
216 					psf->datalength = chunk_size ;
217 
218 					psf->dataoffset = psf_ftell (psf) ;
219 					if (psf->dataoffset < 0)
220 						return SFE_SVX_NO_BODY ;
221 
222 					if (psf->datalength > psf->filelength - psf->dataoffset)
223 					{	psf_log_printf (psf, " BODY : %D (should be %D)\n", psf->datalength, psf->filelength - psf->dataoffset) ;
224 						psf->datalength = psf->filelength - psf->dataoffset ;
225 						}
226 					else
227 						psf_log_printf (psf, " BODY : %D\n", psf->datalength) ;
228 
229 					parsestage |= HAVE_BODY ;
230 
231 					if (! psf->sf.seekable)
232 						break ;
233 
234 					psf_fseek (psf, psf->datalength, SEEK_CUR) ;
235 					break ;
236 
237 			case NAME_MARKER :
238 					if (! (parsestage & HAVE_SVX))
239 						return SFE_SVX_NO_FORM ;
240 
241 					psf_log_printf (psf, " %M : %u\n", marker, chunk_size) ;
242 
243 					if (strlen (psf->file.name.c) != chunk_size)
244 					{	if (chunk_size > sizeof (psf->file.name.c) - 1)
245 							return SFE_SVX_BAD_NAME_LENGTH ;
246 
247 						psf_binheader_readf (psf, "b", psf->file.name.c, chunk_size) ;
248 						psf->file.name.c [chunk_size] = 0 ;
249 						}
250 					else
251 						psf_binheader_readf (psf, "j", chunk_size) ;
252 					break ;
253 
254 			case ANNO_MARKER :
255 					if (! (parsestage & HAVE_SVX))
256 						return SFE_SVX_NO_FORM ;
257 
258 					psf_log_printf (psf, " %M : %u\n", marker, chunk_size) ;
259 
260 					psf_binheader_readf (psf, "j", chunk_size) ;
261 					break ;
262 
263 			case CHAN_MARKER :
264 					if (! (parsestage & HAVE_SVX))
265 						return SFE_SVX_NO_FORM ;
266 
267 					psf_log_printf (psf, " %M : %u\n", marker, chunk_size) ;
268 
269 					bytecount += psf_binheader_readf (psf, "E4", &channels) ;
270 
271 					if (channels == 2 || channels == 4)
272 						psf_log_printf (psf, "  Channels : %d => mono\n", channels) ;
273 					else if (channels == 6)
274 					{	psf->sf.channels = 2 ;
275 						psf_log_printf (psf, "  Channels : %d => stereo\n", channels) ;
276 						}
277 					else
278 						psf_log_printf (psf, "  Channels : %d *** assuming mono\n", channels) ;
279 
280 					psf_binheader_readf (psf, "j", chunk_size - bytecount) ;
281 					break ;
282 
283 
284 			case AUTH_MARKER :
285 			case c_MARKER :
286 					if (! (parsestage & HAVE_SVX))
287 						return SFE_SVX_NO_FORM ;
288 
289 					psf_log_printf (psf, " %M : %u\n", marker, chunk_size) ;
290 
291 					psf_binheader_readf (psf, "j", chunk_size) ;
292 					break ;
293 
294 			default :
295 					if (chunk_size >= 0xffff0000)
296 					{	done = SF_TRUE ;
297 						psf_log_printf (psf, "*** Unknown chunk marker (%X) at position %D with length %u. Exiting parser.\n", marker, psf_ftell (psf) - 8, chunk_size) ;
298 						break ;
299 						} ;
300 
301 					if (psf_isprint ((marker >> 24) & 0xFF) && psf_isprint ((marker >> 16) & 0xFF)
302 						&& psf_isprint ((marker >> 8) & 0xFF) && psf_isprint (marker & 0xFF))
303 					{	psf_log_printf (psf, "%M : %u (unknown marker)\n", marker, chunk_size) ;
304 						psf_binheader_readf (psf, "j", chunk_size) ;
305 						break ;
306 						} ;
307 					if ((chunk_size = psf_ftell (psf)) & 0x03)
308 					{	psf_log_printf (psf, "  Unknown chunk marker at position %d. Resynching.\n", chunk_size - 4) ;
309 
310 						psf_binheader_readf (psf, "j", -3) ;
311 						break ;
312 						} ;
313 					psf_log_printf (psf, "*** Unknown chunk marker (%X) at position %D. Exiting parser.\n", marker, psf_ftell (psf) - 8) ;
314 					done = SF_TRUE ;
315 			} ;	/* switch (marker) */
316 
317 		if (! psf->sf.seekable && (parsestage & HAVE_BODY))
318 			break ;
319 
320 		if (psf_ftell (psf) >= psf->filelength - SIGNED_SIZEOF (chunk_size))
321 			break ;
322 		} ; /* while (1) */
323 
324 	if (vhdr.compression)
325 		return SFE_SVX_BAD_COMP ;
326 
327 	if (psf->dataoffset <= 0)
328 		return SFE_SVX_NO_DATA ;
329 
330 	return 0 ;
331 } /* svx_read_header */
332 
333 static int
svx_close(SF_PRIVATE * psf)334 svx_close (SF_PRIVATE *psf)
335 {
336 	if (psf->file.mode == SFM_WRITE || psf->file.mode == SFM_RDWR)
337 		svx_write_header (psf, SF_TRUE) ;
338 
339 	return 0 ;
340 } /* svx_close */
341 
342 static int
svx_write_header(SF_PRIVATE * psf,int calc_length)343 svx_write_header (SF_PRIVATE *psf, int calc_length)
344 {	static	char 	annotation	[] = "libsndfile by Erik de Castro Lopo\0\0\0" ;
345 	sf_count_t	current ;
346 
347 	current = psf_ftell (psf) ;
348 
349 	if (calc_length)
350 	{	psf->filelength = psf_get_filelen (psf) ;
351 
352 		psf->datalength = psf->filelength - psf->dataoffset ;
353 
354 		if (psf->dataend)
355 			psf->datalength -= psf->filelength - psf->dataend ;
356 
357 		psf->sf.frames = psf->datalength / (psf->bytewidth * psf->sf.channels) ;
358 		} ;
359 
360 	psf->header.ptr [0] = 0 ;
361 	psf->header.indx = 0 ;
362 	psf_fseek (psf, 0, SEEK_SET) ;
363 
364 	/* FORM marker and FORM size. */
365 	psf_binheader_writef (psf, "Etm8", BHWm (FORM_MARKER), BHW8 ((psf->filelength < 8) ?
366 			psf->filelength * 0 : psf->filelength - 8)) ;
367 
368 	psf_binheader_writef (psf, "m", BHWm ((psf->bytewidth == 1) ? SVX8_MARKER : SV16_MARKER)) ;
369 
370 	/* VHDR chunk. */
371 	psf_binheader_writef (psf, "Em4", BHWm (VHDR_MARKER), BHW4 (sizeof (VHDR_CHUNK))) ;
372 	/* VHDR : oneShotHiSamples, repeatHiSamples, samplesPerHiCycle */
373 	psf_binheader_writef (psf, "E444", BHW4 (psf->sf.frames), BHW4 (0), BHW4 (0)) ;
374 	/* VHDR : samplesPerSec, octave, compression */
375 	psf_binheader_writef (psf, "E211", BHW2 (psf->sf.samplerate), BHW1 (1), BHW1 (0)) ;
376 	/* VHDR : volume */
377 	psf_binheader_writef (psf, "E4", BHW4 ((psf->bytewidth == 1) ? 0xFF : 0xFFFF)) ;
378 
379 	if (psf->sf.channels == 2)
380 		psf_binheader_writef (psf, "Em44", BHWm (CHAN_MARKER), BHW4 (4), BHW4 (6)) ;
381 
382 	/* Filename and annotation strings. */
383 	psf_binheader_writef (psf, "Emsms", BHWm (NAME_MARKER), BHWs (psf->file.name.c), BHWm (ANNO_MARKER), BHWs (annotation)) ;
384 
385 	/* BODY marker and size. */
386 	psf_binheader_writef (psf, "Etm8", BHWm (BODY_MARKER), BHW8 ((psf->datalength < 0) ?
387 			psf->datalength * 0 : psf->datalength)) ;
388 
389 	psf_fwrite (psf->header.ptr, psf->header.indx, 1, psf) ;
390 
391 	if (psf->error)
392 		return psf->error ;
393 
394 	psf->dataoffset = psf->header.indx ;
395 
396 	if (current > 0)
397 		psf_fseek (psf, current, SEEK_SET) ;
398 
399 	return psf->error ;
400 } /* svx_write_header */
401 
402