• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2 ** Copyright (C) 2003-2016 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 General Public License as published by
6 ** the Free Software Foundation; either version 2 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 General Public License for more details.
13 **
14 ** You should have received a copy of the GNU 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 <stdlib.h>
23 #include <string.h>
24 #include <math.h>
25 #include <inttypes.h>
26 
27 #if HAVE_UNISTD_H
28 #include <unistd.h>
29 #else
30 #include "sf_unistd.h"
31 #endif
32 
33 #include	<sndfile.h>
34 
35 #include	"utils.h"
36 
37 #define	BUFFER_LEN			(1 << 10)
38 #define LOG_BUFFER_SIZE		1024
39 
40 static void	string_start_test (const char *filename, int typemajor) ;
41 static void	string_start_end_test (const char *filename, int typemajor) ;
42 static void	string_multi_set_test (const char *filename, int typemajor) ;
43 static void	string_rdwr_test (const char *filename, int typemajor) ;
44 static void	string_short_rdwr_test (const char *filename, int typemajor) ;
45 static void	string_rdwr_grow_test (const char *filename, int typemajor) ;
46 static void	string_header_update (const char *filename, int typemajor) ;
47 
48 static void	software_string_test (const char *filename) ;
49 
50 static int str_count (const char * haystack, const char * needle) ;
51 
52 int
main(int argc,char * argv[])53 main (int argc, char *argv [])
54 {	int		do_all = 0 ;
55 	int		test_count = 0 ;
56 
57 	if (argc != 2)
58 	{	printf ("Usage : %s <test>\n", argv [0]) ;
59 		printf ("    Where <test> is one of the following:\n") ;
60 		printf ("           wav  - test adding strings to WAV files\n") ;
61 		printf ("           aiff - test adding strings to AIFF files\n") ;
62 		printf ("           flac - test adding strings to FLAC files\n") ;
63 		printf ("           ogg  - test adding strings to OGG files\n") ;
64 		printf ("           opus - test adding strings to OPUS files\n") ;
65 		printf ("           all  - perform all tests\n") ;
66 		exit (1) ;
67 		} ;
68 
69 	do_all = ! strcmp (argv [1], "all") ;
70 
71 	if (do_all || ! strcmp (argv [1], "wav"))
72 	{	string_start_end_test ("strings.wav", SF_FORMAT_WAV) ;
73 		string_multi_set_test ("multi.wav", SF_FORMAT_WAV) ;
74 		string_rdwr_test ("rdwr.wav", SF_FORMAT_WAV) ;
75 		string_short_rdwr_test ("short_rdwr.wav", SF_FORMAT_WAV) ;
76 		string_rdwr_grow_test ("rdwr_grow.wav", SF_FORMAT_WAV) ;
77 		string_header_update ("header_update.wav", SF_FORMAT_WAV) ;
78 
79 		string_start_end_test ("strings.wavex", SF_FORMAT_WAVEX) ;
80 		string_multi_set_test ("multi.wavex", SF_FORMAT_WAVEX) ;
81 		string_rdwr_test ("rdwr.wavex", SF_FORMAT_WAVEX) ;
82 		string_short_rdwr_test ("short_rdwr.wavex", SF_FORMAT_WAVEX) ;
83 
84 		string_start_end_test ("strings.rifx", SF_ENDIAN_BIG | SF_FORMAT_WAV) ;
85 		string_multi_set_test ("multi.rifx", SF_ENDIAN_BIG | SF_FORMAT_WAV) ;
86 		string_rdwr_test ("rdwr.rifx", SF_ENDIAN_BIG | SF_FORMAT_WAV) ;
87 		string_short_rdwr_test ("short_rdwr.rifx", SF_ENDIAN_BIG | SF_FORMAT_WAV) ;
88 
89 		software_string_test ("software_string.wav") ;
90 		test_count++ ;
91 		} ;
92 
93 	if (do_all || ! strcmp (argv [1], "aiff"))
94 	{	string_start_test ("strings.aiff", SF_FORMAT_AIFF) ;
95 		string_start_end_test ("strings.aiff", SF_FORMAT_AIFF) ;
96 		/*
97 		TODO : Fix src/aiff.c so these tests pass.
98 		string_multi_set_test ("multi.aiff", SF_FORMAT_AIFF) ;
99 		string_rdwr_test ("rdwr.aiff", SF_FORMAT_AIFF) ;
100 		string_short_rdwr_test ("short_rdwr.aiff", SF_FORMAT_AIFF) ;
101 		string_rdwr_grow_test ("rdwr_grow.aiff", SF_FORMAT_AIFF) ;
102 		string_header_update ("header_update.aiff", SF_FORMAT_AIFF) ;
103 		*/
104 
105 		test_count++ ;
106 		} ;
107 
108 	if (do_all || ! strcmp (argv [1], "flac"))
109 	{	if (HAVE_EXTERNAL_XIPH_LIBS)
110 			string_start_test ("strings.flac", SF_FORMAT_FLAC) ;
111 		else
112 			puts ("    No FLAC tests because FLAC support was not compiled in.") ;
113 		test_count++ ;
114 		} ;
115 
116 	if (do_all || ! strcmp (argv [1], "ogg"))
117 	{	if (HAVE_EXTERNAL_XIPH_LIBS)
118 			string_start_test ("vorbis.oga", SF_FORMAT_OGG | SF_FORMAT_VORBIS) ;
119 		else
120 			puts ("    No Ogg/Vorbis tests because Ogg/Vorbis support was not compiled in.") ;
121 		test_count++ ;
122 		} ;
123 
124 	if (do_all || ! strcmp (argv [1], "opus"))
125 	{	if (HAVE_EXTERNAL_XIPH_LIBS)
126 			string_start_test ("opus.opus", SF_FORMAT_OGG | SF_FORMAT_OPUS) ;
127 		else
128 			puts ("    No Ogg/Opus tests because Ogg/Opus support was not compiled in.") ;
129 		test_count++ ;
130 		} ;
131 
132 	if (do_all || ! strcmp (argv [1], "caf"))
133 	{	string_start_test ("strings.caf", SF_FORMAT_CAF) ;
134 		string_start_end_test ("strings.caf", SF_FORMAT_CAF) ;
135 		string_multi_set_test ("multi.caf", SF_FORMAT_CAF) ;
136 		/*
137 		TODO : Fix src/caf.c so these tests pass.
138 		string_rdwr_test ("rdwr.caf", SF_FORMAT_CAF) ;
139 		string_short_rdwr_test ("short_rdwr.caf", SF_FORMAT_CAF) ;
140 		string_header_update ("header_update.caf", SF_FORMAT_CAF) ;
141 		*/
142 		test_count++ ;
143 		} ;
144 
145 	if (do_all || ! strcmp (argv [1], "rf64"))
146 	{	string_start_test ("strings.rf64", SF_FORMAT_RF64) ;
147 		string_start_end_test ("strings.rf64", SF_FORMAT_RF64) ;
148 		string_multi_set_test ("multi.rf64", SF_FORMAT_RF64) ;
149 		/*
150 		TODO : Fix src/rf64.c so these tests pass.
151 		string_rdwr_test ("rdwr.rf64", SF_FORMAT_RF64) ;
152 		string_short_rdwr_test ("short_rdwr.rf64", SF_FORMAT_RF64) ;
153 		string_header_update ("header_update.rf64", SF_FORMAT_RF64) ;
154 		*/
155 		test_count++ ;
156 		} ;
157 
158 	if (do_all || ! strcmp (argv [1], "w64"))
159 	{	puts ("\n\n     **** String test not working yet for W64 format. ****\n") ;
160 		/*
161 		string_start_test ("strings.w64", SF_FORMAT_W64) ;
162 		string_start_end_test ("strings.w64", SF_FORMAT_W64) ;
163 		string_multi_set_test ("multi.w64", SF_FORMAT_W64) ;
164 		string_rdwr_test ("rdwr.w64", SF_FORMAT_W64) ;
165 		string_short_rdwr_test ("short_rdwr.w64", SF_FORMAT_W64) ;
166 		string_header_update ("header_update.w64", SF_FORMAT_W64) ;
167 		*/
168 		test_count++ ;
169 		} ;
170 
171 	if (test_count == 0)
172 	{	printf ("Mono : ************************************\n") ;
173 		printf ("Mono : *  No '%s' test defined.\n", argv [1]) ;
174 		printf ("Mono : ************************************\n") ;
175 		return 1 ;
176 		} ;
177 
178 	return 0 ;
179 } /* main */
180 
181 
182 /*============================================================================================
183 **	Here are the test functions.
184 */
185 
186 static const char
187 	software	[]	= "software (libsndfile-X.Y.Z)",
188 	artist		[]	= "The Artist",
189 	copyright	[]	= "Copyright (c) 2001 Artist",
190 	comment		[]	= "Comment goes here!!!",
191 	date		[]	= "2001/01/27",
192 	album		[]	= "The Album",
193 	license		[]	= "The license",
194 	title		[]	= "This is the title",
195 	long_title	[]	= "This is a very long and very boring title for this file",
196 	long_artist	[]	= "The artist who kept on changing its name",
197 	genre		[]	= "The genre",
198 	trackno		[]	= "Track three" ;
199 
200 
201 static	short	data_out [BUFFER_LEN] ;
202 
203 static void
string_start_end_test(const char * filename,int typemajor)204 string_start_end_test (const char *filename, int typemajor)
205 {	const char	*cptr ;
206 	SNDFILE		*file ;
207 	SF_INFO		sfinfo ;
208 	int			errors = 0 ;
209 
210 	print_test_name ("string_start_end_test", filename) ;
211 
212 	memset (&sfinfo, 0, sizeof (sfinfo)) ;
213 	sfinfo.samplerate	= 44100 ;
214 	sfinfo.channels		= 1 ;
215 	sfinfo.frames		= 0 ;
216 	sfinfo.format		= typemajor | SF_FORMAT_PCM_16 ;
217 
218 	file = test_open_file_or_die (filename, SFM_WRITE, &sfinfo, SF_TRUE, __LINE__) ;
219 
220 	/* Write stuff at start of file. */
221 	sf_set_string (file, SF_STR_TITLE, filename) ;
222 	sf_set_string (file, SF_STR_SOFTWARE, software) ;
223 	sf_set_string (file, SF_STR_ARTIST, artist) ;
224 	sf_set_string (file, SF_STR_GENRE, genre) ;
225 	sf_set_string (file, SF_STR_TRACKNUMBER, trackno) ;
226 
227 	/* Write data to file. */
228 	test_write_short_or_die (file, 0, data_out, BUFFER_LEN, __LINE__) ;
229 	test_seek_or_die (file, 0, SEEK_SET, 0, sfinfo.channels, __LINE__) ;
230 
231 	/* Write more stuff at end of file. */
232 	sf_set_string (file, SF_STR_COPYRIGHT, copyright) ;
233 	sf_set_string (file, SF_STR_COMMENT, comment) ;
234 	sf_set_string (file, SF_STR_DATE, date) ;
235 	sf_set_string (file, SF_STR_ALBUM, album) ;
236 	sf_set_string (file, SF_STR_LICENSE, license) ;
237 
238 	sf_close (file) ;
239 
240 	file = test_open_file_or_die (filename, SFM_READ, &sfinfo, SF_TRUE, __LINE__) ;
241 
242 	check_log_buffer_or_die (file, __LINE__) ;
243 
244 	if (sfinfo.frames != BUFFER_LEN)
245 	{	printf ("***** Bad frame count %d (should be %d)\n\n", (int) sfinfo.frames, BUFFER_LEN) ;
246 		errors ++ ;
247 		} ;
248 
249 	cptr = sf_get_string (file, SF_STR_TITLE) ;
250 	if (cptr == NULL || strcmp (filename, cptr) != 0)
251 	{	if (errors++ == 0)
252 			puts ("\n") ;
253 		printf ("    Bad filename  : %s\n", cptr) ;
254 		} ;
255 
256 	cptr = sf_get_string (file, SF_STR_COPYRIGHT) ;
257 	if (cptr == NULL || strcmp (copyright, cptr) != 0)
258 	{	if (errors++ == 0)
259 			puts ("\n") ;
260 		printf ("    Bad copyright : %s\n", cptr) ;
261 		} ;
262 
263 	cptr = sf_get_string (file, SF_STR_SOFTWARE) ;
264 	if (cptr == NULL || strstr (cptr, software) != cptr)
265 	{	if (errors++ == 0)
266 			puts ("\n") ;
267 		printf ("    Bad software  : %s\n", cptr) ;
268 		} ;
269 
270 	if (str_count (cptr, "libsndfile") != 1)
271 	{	if (errors++ == 0)
272 			puts ("\n") ;
273 		printf ("    Bad software  : %s\n", cptr) ;
274 		} ;
275 
276 	cptr = sf_get_string (file, SF_STR_ARTIST) ;
277 	if (cptr == NULL || strcmp (artist, cptr) != 0)
278 	{	if (errors++ == 0)
279 			puts ("\n") ;
280 		printf ("    Bad artist    : %s\n", cptr) ;
281 		} ;
282 
283 	cptr = sf_get_string (file, SF_STR_COMMENT) ;
284 	if (cptr == NULL || strcmp (comment, cptr) != 0)
285 	{	if (errors++ == 0)
286 			puts ("\n") ;
287 		printf ("    Bad comment   : %s\n", cptr) ;
288 		} ;
289 
290 	if (typemajor != SF_FORMAT_AIFF)
291 	{	cptr = sf_get_string (file, SF_STR_DATE) ;
292 		if (cptr == NULL || strcmp (date, cptr) != 0)
293 		{	if (errors++ == 0)
294 				puts ("\n") ;
295 			printf ("    Bad date      : %s\n", cptr) ;
296 			} ;
297 
298 		cptr = sf_get_string (file, SF_STR_GENRE) ;
299 		if (cptr == NULL || strcmp (genre, cptr) != 0)
300 		{	if (errors++ == 0)
301 				puts ("\n") ;
302 			printf ("    Bad genre     : %s\n", cptr) ;
303 			} ;
304 		} ;
305 
306 	switch (typemajor)
307 	{	case SF_FORMAT_AIFF :
308 		case SF_FORMAT_WAV :
309 		case SF_FORMAT_WAVEX :
310 		case SF_ENDIAN_BIG | SF_FORMAT_WAV :
311 		case SF_FORMAT_RF64 :
312 			/* These formats do not support the following. */
313 			break ;
314 
315 		default :
316 			cptr = sf_get_string (file, SF_STR_ALBUM) ;
317 			if (cptr == NULL || strcmp (album, cptr) != 0)
318 			{	if (errors++ == 0)
319 					puts ("\n") ;
320 				printf ("    Bad album     : %s\n", cptr) ;
321 				} ;
322 
323 			cptr = sf_get_string (file, SF_STR_LICENSE) ;
324 			if (cptr == NULL || strcmp (license, cptr) != 0)
325 			{	if (errors++ == 0)
326 					puts ("\n") ;
327 				printf ("    Bad license   : %s\n", cptr) ;
328 				} ;
329 
330 			cptr = sf_get_string (file, SF_STR_TRACKNUMBER) ;
331 			if (cptr == NULL || strcmp (trackno, cptr) != 0)
332 			{	if (errors++ == 0)
333 					puts ("\n") ;
334 				printf ("    Bad track no. : %s\n", cptr) ;
335 				} ;
336 			break ;
337 		} ;
338 
339 	if (errors > 0)
340 	{	printf ("\n*** Error count : %d ***\n\n", errors) ;
341 		dump_log_buffer (file) ;
342 		exit (1) ;
343 		} ;
344 
345 	sf_close (file) ;
346 	unlink (filename) ;
347 
348 	puts ("ok") ;
349 } /* string_start_end_test */
350 
351 static void
string_start_test(const char * filename,int formattype)352 string_start_test (const char *filename, int formattype)
353 {	const char	*cptr ;
354 	SNDFILE		*file ;
355 	SF_INFO		sfinfo ;
356 	int			errors = 0 ;
357 	int			typemajor = SF_FORMAT_TYPEMASK & formattype ;
358 
359 	print_test_name ("string_start_test", filename) ;
360 
361 	memset (&sfinfo, 0, sizeof (sfinfo)) ;
362 	sfinfo.samplerate	= 44100 ;
363 	sfinfo.channels		= 1 ;
364 	sfinfo.frames		= 0 ;
365 
366 	switch (formattype)
367 	{	case SF_FORMAT_OGG | SF_FORMAT_OPUS :
368 			/* Opus only supports some discrete sample rates. */
369 			sfinfo.samplerate = 48000 ;
370 			break ;
371 
372 		case SF_FORMAT_OGG | SF_FORMAT_VORBIS :
373 			break ;
374 
375 		default :
376 			formattype |= SF_FORMAT_PCM_16 ;
377 			break ;
378 		} ;
379 	sfinfo.format = formattype ;
380 
381 	file = test_open_file_or_die (filename, SFM_WRITE, &sfinfo, SF_TRUE, __LINE__) ;
382 
383 	/* Write stuff at start of file. */
384 	sf_set_string (file, SF_STR_TITLE, filename) ;
385 	sf_set_string (file, SF_STR_SOFTWARE, software) ;
386 	sf_set_string (file, SF_STR_ARTIST, artist) ;
387 	sf_set_string (file, SF_STR_COPYRIGHT, copyright) ;
388 	sf_set_string (file, SF_STR_COMMENT, comment) ;
389 	sf_set_string (file, SF_STR_DATE, date) ;
390 	sf_set_string (file, SF_STR_ALBUM, album) ;
391 	sf_set_string (file, SF_STR_LICENSE, license) ;
392 
393 	/* Write data to file. */
394 	test_write_short_or_die (file, 0, data_out, BUFFER_LEN, __LINE__) ;
395 
396 	sf_close (file) ;
397 
398 	file = test_open_file_or_die (filename, SFM_READ, &sfinfo, SF_TRUE, __LINE__) ;
399 
400 	check_log_buffer_or_die (file, __LINE__) ;
401 
402 	if (sfinfo.frames != BUFFER_LEN)
403 	{	printf ("***** Bad frame count %d (should be %d)\n\n", (int) sfinfo.frames, BUFFER_LEN) ;
404 		errors ++ ;
405 		} ;
406 
407 	cptr = sf_get_string (file, SF_STR_TITLE) ;
408 	if (cptr == NULL || strcmp (filename, cptr) != 0)
409 	{	if (errors++ == 0)
410 			puts ("\n") ;
411 		printf ("    Bad filename  : %s\n", cptr) ;
412 		} ;
413 
414 	cptr = sf_get_string (file, SF_STR_COPYRIGHT) ;
415 	if (cptr == NULL || strcmp (copyright, cptr) != 0)
416 	{	if (errors++ == 0)
417 			puts ("\n") ;
418 		printf ("    Bad copyright : %s\n", cptr) ;
419 		} ;
420 
421 	cptr = sf_get_string (file, SF_STR_SOFTWARE) ;
422 	if (cptr == NULL || strstr (cptr, software) != cptr)
423 	{	if (errors++ == 0)
424 			puts ("\n") ;
425 		printf ("    Bad software  : %s\n", cptr) ;
426 		} ;
427 
428 	if (cptr && str_count (cptr, "libsndfile") != 1)
429 	{	if (errors++ == 0)
430 			puts ("\n") ;
431 		printf ("    Bad software  : %s\n", cptr) ;
432 		} ;
433 
434 	cptr = sf_get_string (file, SF_STR_ARTIST) ;
435 	if (cptr == NULL || strcmp (artist, cptr) != 0)
436 	{	if (errors++ == 0)
437 			puts ("\n") ;
438 		printf ("    Bad artist    : %s\n", cptr) ;
439 		} ;
440 
441 	cptr = sf_get_string (file, SF_STR_COMMENT) ;
442 	if (cptr == NULL || strcmp (comment, cptr) != 0)
443 	{	if (errors++ == 0)
444 			puts ("\n") ;
445 		printf ("    Bad comment   : %s\n", cptr) ;
446 		} ;
447 
448 	if (typemajor != SF_FORMAT_AIFF)
449 	{	cptr = sf_get_string (file, SF_STR_DATE) ;
450 		if (cptr == NULL || strcmp (date, cptr) != 0)
451 		{	if (errors++ == 0)
452 				puts ("\n") ;
453 			printf ("    Bad date      : %s\n", cptr) ;
454 			} ;
455 		} ;
456 
457 	if (typemajor != SF_FORMAT_WAV && typemajor != SF_FORMAT_AIFF)
458 	{	cptr = sf_get_string (file, SF_STR_ALBUM) ;
459 		if (cptr == NULL || strcmp (album, cptr) != 0)
460 		{	if (errors++ == 0)
461 				puts ("\n") ;
462 			printf ("    Bad album     : %s\n", cptr) ;
463 			} ;
464 		} ;
465 
466 	if (typemajor != SF_FORMAT_WAV && typemajor != SF_FORMAT_AIFF && typemajor != SF_FORMAT_RF64)
467 	{	cptr = sf_get_string (file, SF_STR_LICENSE) ;
468 		if (cptr == NULL || strcmp (license, cptr) != 0)
469 		{	if (errors++ == 0)
470 				puts ("\n") ;
471 			printf ("    Bad license   : %s\n", cptr) ;
472 			} ;
473 		} ;
474 
475 	if (errors > 0)
476 	{	printf ("\n*** Error count : %d ***\n\n", errors) ;
477 		dump_log_buffer (file) ;
478 		exit (1) ;
479 		} ;
480 
481 	sf_close (file) ;
482 	unlink (filename) ;
483 
484 	puts ("ok") ;
485 } /* string_start_test */
486 
487 static void
string_multi_set_test(const char * filename,int typemajor)488 string_multi_set_test (const char *filename, int typemajor)
489 {	static const char
490 		new_software	[]	= "new software (libsndfile-X.Y.Z)",
491 		new_copyright	[]	= "Copyright (c) 2001 New Artist",
492 		new_artist		[]	= "The New Artist",
493 		new_title		[]	= "This is the new title" ;
494 
495 	static char buffer [2048] ;
496 	SNDFILE		*file ;
497 	SF_INFO		sfinfo ;
498 	int			count ;
499 
500 	print_test_name (__func__, filename) ;
501 
502 	memset (&sfinfo, 0, sizeof (sfinfo)) ;
503 	sfinfo.format		= typemajor | SF_FORMAT_PCM_16 ;
504 	sfinfo.samplerate	= 44100 ;
505 	sfinfo.channels		= 1 ;
506 	sfinfo.frames		= 0 ;
507 
508 	file = test_open_file_or_die (filename, SFM_WRITE, &sfinfo, SF_TRUE, __LINE__) ;
509 
510 	/* Write stuff at start of file. */
511 	sf_set_string (file, SF_STR_TITLE, title) ;
512 	sf_set_string (file, SF_STR_SOFTWARE, software) ;
513 	sf_set_string (file, SF_STR_ARTIST, artist) ;
514 
515 	/* Write data to file. */
516 	test_write_short_or_die (file, 0, data_out, BUFFER_LEN, __LINE__) ;
517 
518 	/* Write it all again. */
519 
520 	sf_set_string (file, SF_STR_TITLE, new_title) ;
521 	sf_set_string (file, SF_STR_SOFTWARE, new_software) ;
522 	sf_set_string (file, SF_STR_ARTIST, new_artist) ;
523 
524 	sf_set_string (file, SF_STR_COPYRIGHT, copyright) ;
525 	sf_set_string (file, SF_STR_COMMENT, comment) ;
526 	sf_set_string (file, SF_STR_DATE, date) ;
527 	sf_set_string (file, SF_STR_ALBUM, album) ;
528 	sf_set_string (file, SF_STR_LICENSE, license) ;
529 	sf_set_string (file, SF_STR_COPYRIGHT, new_copyright) ;
530 	sf_set_string (file, SF_STR_COMMENT, comment) ;
531 	sf_set_string (file, SF_STR_DATE, date) ;
532 	sf_set_string (file, SF_STR_ALBUM, album) ;
533 	sf_set_string (file, SF_STR_LICENSE, license) ;
534 
535 	sf_close (file) ;
536 
537 	file = test_open_file_or_die (filename, SFM_READ, &sfinfo, SF_TRUE, __LINE__) ;
538 	sf_command	(file, SFC_GET_LOG_INFO, buffer, sizeof (buffer)) ;
539 	sf_close (file) ;
540 
541 	count = str_count (buffer, new_title) ;
542 	exit_if_true (count < 1, "\n\nLine %d : Could not find new_title in :\n%s\n", __LINE__, buffer) ;
543 	exit_if_true (count > 1, "\n\nLine %d : new_title appears %d times in :\n\n%s\n", __LINE__, count, buffer) ;
544 
545 	count = str_count (buffer, software) ;
546 	exit_if_true (count < 1, "\n\nLine %d : Could not find new_software in :\n%s\n", __LINE__, buffer) ;
547 	exit_if_true (count > 1, "\n\nLine %d : new_software appears %d times in :\n\n%s\n", __LINE__, count, buffer) ;
548 
549 	count = str_count (buffer, new_artist) ;
550 	exit_if_true (count < 1, "\n\nLine %d : Could not find new_artist in :\n%s\n", __LINE__, buffer) ;
551 	exit_if_true (count > 1, "\n\nLine %d : new_artist appears %d times in :\n\n%s\n", __LINE__, count, buffer) ;
552 
553 	count = str_count (buffer, new_copyright) ;
554 	exit_if_true (count < 1, "\n\nLine %d : Could not find new_copyright in :\n%s\n", __LINE__, buffer) ;
555 	exit_if_true (count > 1, "\n\nLine %d : new_copyright appears %d times in :\n\n%s\n", __LINE__, count, buffer) ;
556 
557 	unlink (filename) ;
558 
559 	puts ("ok") ;
560 } /* string_multi_set_test */
561 
562 static void
string_rdwr_test(const char * filename,int typemajor)563 string_rdwr_test (const char *filename, int typemajor)
564 {	SNDFILE *file ;
565 	SF_INFO sfinfo ;
566 	sf_count_t frames ;
567 	const char * str ;
568 
569 	print_test_name (__func__, filename) ;
570 	create_short_sndfile (filename, typemajor | SF_FORMAT_PCM_16, 2) ;
571 
572 	memset (&sfinfo, 0, sizeof (sfinfo)) ;
573 	file = test_open_file_or_die (filename, SFM_RDWR, &sfinfo, SF_FALSE, __LINE__) ;
574 	frames = sfinfo.frames ;
575 	sf_set_string (file, SF_STR_TITLE, title) ;
576 	sf_close (file) ;
577 
578 	file = test_open_file_or_die (filename, SFM_READ, &sfinfo, SF_FALSE, __LINE__) ;
579 	exit_if_true (frames != sfinfo.frames, "\n\nLine %d : Frame count %" PRId64 " should be %" PRId64 ".\n", __LINE__, sfinfo.frames, frames) ;
580 	str = sf_get_string (file, SF_STR_TITLE) ;
581 	exit_if_true (str == NULL, "\n\nLine %d : SF_STR_TITLE string is NULL.\n", __LINE__) ;
582 	exit_if_true (strcmp (str, title) != 0, "\n\nLine %d : SF_STR_TITLE doesn't match what was written.\n", __LINE__) ;
583 	sf_close (file) ;
584 
585 	file = test_open_file_or_die (filename, SFM_RDWR, &sfinfo, SF_FALSE, __LINE__) ;
586 	frames = sfinfo.frames ;
587 	sf_set_string (file, SF_STR_TITLE, title) ;
588 	sf_close (file) ;
589 
590 	file = test_open_file_or_die (filename, SFM_RDWR, &sfinfo, SF_FALSE, __LINE__) ;
591 	str = sf_get_string (file, SF_STR_TITLE) ;
592 	exit_if_true (str == NULL, "\n\nLine %d : SF_STR_TITLE string is NULL.\n", __LINE__) ;
593 	sf_set_string (file, SF_STR_ARTIST, artist) ;
594 	sf_close (file) ;
595 
596 	file = test_open_file_or_die (filename, SFM_READ, &sfinfo, SF_FALSE, __LINE__) ;
597 
598 	str = sf_get_string (file, SF_STR_ARTIST) ;
599 	exit_if_true (str == NULL, "\n\nLine %d : SF_STR_ARTIST string is NULL.\n", __LINE__) ;
600 	exit_if_true (strcmp (str, artist) != 0, "\n\nLine %d : SF_STR_ARTIST doesn't match what was written.\n", __LINE__) ;
601 
602 	str = sf_get_string (file, SF_STR_TITLE) ;
603 	exit_if_true (str == NULL, "\n\nLine %d : SF_STR_TITLE string is NULL.\n", __LINE__) ;
604 	exit_if_true (strcmp (str, title) != 0, "\n\nLine %d : SF_STR_TITLE doesn't match what was written.\n", __LINE__) ;
605 
606 	exit_if_true (frames != sfinfo.frames, "\n\nLine %d : Frame count %" PRId64 " should be %" PRId64 ".\n", __LINE__, sfinfo.frames, frames) ;
607 
608 	sf_close (file) ;
609 	unlink (filename) ;
610 
611 	puts ("ok") ;
612 } /* string_rdwr_test */
613 
614 static void
string_short_rdwr_test(const char * filename,int typemajor)615 string_short_rdwr_test (const char *filename, int typemajor)
616 {	SNDFILE *file ;
617 	SF_INFO sfinfo ;
618 	sf_count_t frames = BUFFER_LEN ;
619 	const char * str ;
620 
621 	print_test_name (__func__, filename) ;
622 
623 	memset (&sfinfo, 0, sizeof (sfinfo)) ;
624 	sfinfo.format		= typemajor | SF_FORMAT_PCM_16 ;
625 	sfinfo.samplerate	= 44100 ;
626 	sfinfo.channels		= 1 ;
627 	sfinfo.frames		= 0 ;
628 
629 	file = test_open_file_or_die (filename, SFM_WRITE, &sfinfo, SF_FALSE, __LINE__) ;
630 
631 	/* Write data to file. */
632 	test_write_short_or_die (file, 0, data_out, BUFFER_LEN, __LINE__) ;
633 
634 	sf_set_string (file, SF_STR_TITLE, long_title) ;
635 	sf_set_string (file, SF_STR_ARTIST, long_artist) ;
636 	sf_close (file) ;
637 
638 	/* Open the file RDWR. */
639 	file = test_open_file_or_die (filename, SFM_RDWR, &sfinfo, SF_FALSE, __LINE__) ;
640 	exit_if_true (frames != sfinfo.frames, "\n\nLine %d : Frame count %" PRId64 " should be %" PRId64 ".\n", __LINE__, sfinfo.frames, frames) ;
641 	str = sf_get_string (file, SF_STR_TITLE) ;
642 	exit_if_true (str == NULL, "\n\nLine %d : SF_STR_TITLE string is NULL.\n", __LINE__) ;
643 	exit_if_true (strcmp (str, long_title) != 0, "\n\nLine %d : SF_STR_TITLE doesn't match what was written.\n", __LINE__) ;
644 	str = sf_get_string (file, SF_STR_ARTIST) ;
645 	exit_if_true (str == NULL, "\n\nLine %d : SF_STR_TITLE string is NULL.\n", __LINE__) ;
646 	exit_if_true (strcmp (str, long_artist) != 0, "\n\nLine %d : SF_STR_ARTIST doesn't match what was written.\n", __LINE__) ;
647 
648 	/* Change title and artist. */
649 	sf_set_string (file, SF_STR_TITLE, title) ;
650 	sf_set_string (file, SF_STR_ARTIST, artist) ;
651 
652 	sf_close (file) ;
653 
654 	file = test_open_file_or_die (filename, SFM_READ, &sfinfo, SF_FALSE, __LINE__) ;
655 
656 	check_log_buffer_or_die (file, __LINE__) ;
657 
658 	str = sf_get_string (file, SF_STR_TITLE) ;
659 	exit_if_true (str == NULL, "\n\nLine %d : SF_STR_TITLE string is NULL.\n", __LINE__) ;
660 	exit_if_true (strcmp (str, title) != 0, "\n\nLine %d : SF_STR_TITLE doesn't match what was written.\n", __LINE__) ;
661 
662 	str = sf_get_string (file, SF_STR_ARTIST) ;
663 	exit_if_true (str == NULL, "\n\nLine %d : SF_STR_ARTIST string is NULL.\n", __LINE__) ;
664 	exit_if_true (strcmp (str, artist) != 0, "\n\nLine %d : SF_STR_ARTIST doesn't match what was written.\n", __LINE__) ;
665 
666 	sf_close (file) ;
667 	unlink (filename) ;
668 
669 	puts ("ok") ;
670 } /* string_short_rdwr_test */
671 
672 static int
str_count(const char * haystack,const char * needle)673 str_count (const char * haystack, const char * needle)
674 {	int count = 0 ;
675 
676 	while ((haystack = strstr (haystack, needle)) != NULL)
677 	{	count ++ ;
678 		haystack ++ ;
679 		} ;
680 
681 	return count ;
682 } /* str_count */
683 
684 #define MIN(a, b)	((a) < (b) ? (a) : (b))
685 
686 static void
software_string_test(const char * filename)687 software_string_test (const char *filename)
688 {	size_t k ;
689 
690 	print_test_name (__func__, filename) ;
691 
692 	for (k = 0 ; k < 50 ; k++)
693 	{	const char *result ;
694 		char sfname [64] = "" ;
695 		SNDFILE *file ;
696 		SF_INFO info ;
697 
698 		sf_info_setup (&info, SF_FORMAT_WAV | SF_FORMAT_PCM_16, 44100, 1) ;
699 		file = test_open_file_or_die (filename, SFM_WRITE, &info, SF_TRUE, __LINE__) ;
700 
701 		snprintf (sfname, MIN (k, sizeof (sfname)), "%s", "abcdefghijklmnopqrestvwxyz0123456789abcdefghijklmnopqrestvwxyz") ;
702 
703 		exit_if_true (sf_set_string (file, SF_STR_SOFTWARE, sfname),
704 			"\n\nLine %d : sf_set_string (f, SF_STR_SOFTWARE, '%s') failed : %s\n", __LINE__, sfname, sf_strerror (file)) ;
705 
706 		sf_close (file) ;
707 
708 		file = test_open_file_or_die (filename, SFM_READ, &info, SF_TRUE, __LINE__) ;
709 		result = sf_get_string (file, SF_STR_SOFTWARE) ;
710 
711 		exit_if_true (result == NULL, "\n\nLine %d : sf_get_string (file, SF_STR_SOFTWARE) returned NULL.\n\n", __LINE__) ;
712 
713 		exit_if_true (strstr (result, sfname) != result,
714 			"\n\nLine %d : Can't fine string '%s' in '%s'\n\n", __LINE__, sfname, result) ;
715 		sf_close (file) ;
716 		} ;
717 
718 	unlink (filename) ;
719 	puts ("ok") ;
720 } /* software_string_test */
721 
722 
723 static void
string_rdwr_grow_test(const char * filename,int typemajor)724 string_rdwr_grow_test (const char *filename, int typemajor)
725 {	SNDFILE *file ;
726 	SF_INFO sfinfo ;
727 	sf_count_t frames ;
728 	const char * str ;
729 
730 	print_test_name (__func__, filename) ;
731 
732 	/* Create a file that contains some strings. Then open the file in RDWR mode and
733 		 grow the file by writing more audio data to it. Check that the audio data has
734 		 been added to the file, and that the strings are still there. */
735 
736 	/* Create a short file that contains a string. */
737 	memset (&sfinfo, 0, sizeof (sfinfo)) ;
738 	sfinfo.samplerate	= 44100 ;
739 	sfinfo.channels		= 2 ;
740 	sfinfo.frames		= 0 ;
741 	sfinfo.format		= typemajor | SF_FORMAT_PCM_16 ;
742 
743 	file = test_open_file_or_die (filename, SFM_WRITE, &sfinfo, SF_TRUE, __LINE__) ;
744 	/* Write data to file. */
745 	test_write_short_or_die (file, 0, data_out, BUFFER_LEN, __LINE__) ;
746 
747 	/* Write some strings at end of file. */
748 	sf_set_string (file, SF_STR_TITLE , title) ;
749 	sf_set_string (file, SF_STR_COMMENT, comment) ;
750 	sf_close (file) ;
751 
752 
753 	/* Now open file again in SFM_RDWR mode and write more audio data to it. */
754 	file = test_open_file_or_die (filename, SFM_RDWR, &sfinfo, SF_TRUE, __LINE__) ;
755 	/* Write more data to file.  */
756 	test_write_short_or_die (file, 0, data_out, BUFFER_LEN, __LINE__) ;
757 	sf_close (file) ;
758 
759 
760 	/* Now open file again. It should now contain two BUFFER_LEN's worth of frames and the strings. */
761 	frames = 2 * BUFFER_LEN / sfinfo.channels ;
762 	file = test_open_file_or_die (filename, SFM_READ, &sfinfo, SF_TRUE, __LINE__) ;
763 	exit_if_true (frames != sfinfo.frames, "\n\nLine %d : Frame count %" PRId64 " should be %" PRId64 ".\n", __LINE__, sfinfo.frames, frames) ;
764 
765 	/* Check the strings */
766 	str = sf_get_string (file, SF_STR_TITLE) ;
767 	exit_if_true (str == NULL, "\n\nLine %d : SF_STR_TITLE string is NULL.\n", __LINE__) ;
768 	exit_if_true (strcmp (str, title) != 0, "\n\nLine %d : SF_STR_TITLE doesn't match what was written.\n", __LINE__) ;
769 
770 	str = sf_get_string (file, SF_STR_COMMENT) ;
771 	exit_if_true (str == NULL, "\n\nLine %d : SF_STR_COMMENT string is NULL.\n", __LINE__) ;
772 	exit_if_true (strcmp (str, comment) != 0, "\n\nLine %d : SF_STR_COMMENT doesn't match what was written.\n", __LINE__) ;
773 
774 	sf_close (file) ;
775 	unlink (filename) ;
776 
777 	puts ("ok") ;
778 } /* string_rdwr_grow_test */
779 
780 static void
string_header_update(const char * filename,int typemajor)781 string_header_update (const char *filename, int typemajor)
782 {	SNDFILE *file , *file1 ;
783 	SF_INFO sfinfo , sfinfo1 ;
784 	sf_count_t frames ;
785 	const char * str ;
786 	const int GROW_BUFFER_AMOUNT = 4 ; /* this should be less than half the size of the string header */
787 
788 	print_test_name (__func__, filename) ;
789 
790 	/* Create a short file. */
791 	memset (&sfinfo, 0, sizeof (sfinfo)) ;
792 	sfinfo.samplerate	= 44100 ;
793 	sfinfo.channels		= 2 ;
794 	sfinfo.frames		= 0 ;
795 	sfinfo.format		= typemajor | SF_FORMAT_PCM_16 ;
796 
797 	file = test_open_file_or_die (filename, SFM_WRITE, &sfinfo, SF_TRUE, __LINE__) ;
798 	test_write_short_or_die (file, 0, data_out, BUFFER_LEN, __LINE__) ;
799 	sf_set_string (file, SF_STR_TITLE, long_title) ;
800 	sf_close (file) ;
801 
802 
803 	/* Check that SFC_UPDATE_HEADER_NOW correctly calculates datalength. */
804 	file = test_open_file_or_die (filename, SFM_RDWR, &sfinfo, SF_TRUE, __LINE__) ;
805 	/* Write a very small amount of new audio data that doesn't completely overwrite the existing header. */
806 	test_write_short_or_die (file, 0, data_out, GROW_BUFFER_AMOUNT, __LINE__) ;
807 
808 	/* Update the header without closing the file. */
809 	sf_command (file, SFC_UPDATE_HEADER_NOW, NULL, 0) ;
810 
811 	/* The file should now contain BUFFER_LEN + GROW_BUFFER_AMOUNT frames.
812 		Open a second handle to the file and check the reported length. */
813 	memset (&sfinfo1, 0, sizeof (sfinfo1)) ;
814 	file1 = test_open_file_or_die (filename, SFM_READ, &sfinfo1, SF_TRUE, __LINE__) ;
815 
816 	frames = (BUFFER_LEN + GROW_BUFFER_AMOUNT) / sfinfo.channels ;
817 	exit_if_true (frames != sfinfo1.frames, "\n\nLine %d : Frame count %" PRId64 " should be %" PRId64 ".\n", __LINE__, sfinfo1.frames, frames) ;
818 
819 	/* The strings are probably not readable by the second soundfile handle because write_tailer has not yet been called.
820 		It's a design decision whether SFC_UPDATE_HEADER_NOW should write the tailer. I think it's fine that it doesn't.  */
821 
822 	sf_close (file1) ;
823 	sf_close (file) ;
824 
825 
826 	/* Check that sf_close correctly calculates datalength. */
827 	file = test_open_file_or_die (filename, SFM_RDWR, &sfinfo, SF_TRUE, __LINE__) ;
828 	/* Write a very small amount of new audio data that doesn't completely overwrite the existing header. */
829 	test_write_short_or_die (file, 0, data_out, GROW_BUFFER_AMOUNT, __LINE__) ;
830 	sf_close (file) ;
831 
832 
833 	/* Open file again and verify data and string. */
834 	file = test_open_file_or_die (filename, SFM_READ, &sfinfo, SF_TRUE, __LINE__) ;
835 	frames = (BUFFER_LEN + 2*GROW_BUFFER_AMOUNT) / sfinfo.channels ;
836 	exit_if_true (frames != sfinfo.frames, "\n\nLine %d : Frame count %" PRId64 " should be %" PRId64 ".\n", __LINE__, sfinfo.frames, frames) ;
837 	str = sf_get_string (file, SF_STR_TITLE) ;
838 	exit_if_true (str == NULL, "\n\nLine %d : SF_STR_TITLE string is NULL.\n", __LINE__) ;
839 	exit_if_true (strcmp (str, long_title) != 0, "\n\nLine %d : SF_STR_TITLE doesn't match what was written.\n", __LINE__) ;
840 	sf_close (file) ;
841 	unlink (filename) ;
842 	puts ("ok") ;
843 } /* string_header_update */
844