xref: /aosp_15_r20/external/flac/src/test_libFLAC/metadata_manip.c (revision 600f14f40d737144c998e2ec7a483122d3776fbc)
1*600f14f4SXin Li /* test_libFLAC - Unit tester for libFLAC
2*600f14f4SXin Li  * Copyright (C) 2002-2009  Josh Coalson
3*600f14f4SXin Li  * Copyright (C) 2011-2023  Xiph.Org Foundation
4*600f14f4SXin Li  *
5*600f14f4SXin Li  * This program is free software; you can redistribute it and/or
6*600f14f4SXin Li  * modify it under the terms of the GNU General Public License
7*600f14f4SXin Li  * as published by the Free Software Foundation; either version 2
8*600f14f4SXin Li  * of the License, or (at your option) any later version.
9*600f14f4SXin Li  *
10*600f14f4SXin Li  * This program is distributed in the hope that it will be useful,
11*600f14f4SXin Li  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12*600f14f4SXin Li  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13*600f14f4SXin Li  * GNU General Public License for more details.
14*600f14f4SXin Li  *
15*600f14f4SXin Li  * You should have received a copy of the GNU General Public License along
16*600f14f4SXin Li  * with this program; if not, write to the Free Software Foundation, Inc.,
17*600f14f4SXin Li  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18*600f14f4SXin Li  */
19*600f14f4SXin Li 
20*600f14f4SXin Li #ifdef HAVE_CONFIG_H
21*600f14f4SXin Li #  include <config.h>
22*600f14f4SXin Li #endif
23*600f14f4SXin Li 
24*600f14f4SXin Li #include <stdio.h>
25*600f14f4SXin Li #include <stdlib.h> /* for malloc() */
26*600f14f4SXin Li #include <string.h> /* for memcpy()/memset() */
27*600f14f4SXin Li #if defined _MSC_VER || defined __MINGW32__
28*600f14f4SXin Li #include <sys/utime.h> /* for utime() */
29*600f14f4SXin Li #include <io.h> /* for chmod() */
30*600f14f4SXin Li #else
31*600f14f4SXin Li #include <sys/types.h> /* some flavors of BSD (like OS X) require this to get time_t */
32*600f14f4SXin Li #include <unistd.h> /* for chown(), unlink() */
33*600f14f4SXin Li #endif
34*600f14f4SXin Li #include <sys/stat.h> /* for stat(), maybe chmod() */
35*600f14f4SXin Li #include "FLAC/assert.h"
36*600f14f4SXin Li #include "FLAC/stream_decoder.h"
37*600f14f4SXin Li #include "FLAC/metadata.h"
38*600f14f4SXin Li #include "share/grabbag.h"
39*600f14f4SXin Li #include "share/compat.h"
40*600f14f4SXin Li #include "share/macros.h"
41*600f14f4SXin Li #include "share/safe_str.h"
42*600f14f4SXin Li #include "test_libs_common/file_utils_flac.h"
43*600f14f4SXin Li #include "test_libs_common/metadata_utils.h"
44*600f14f4SXin Li #include "metadata.h"
45*600f14f4SXin Li 
46*600f14f4SXin Li 
47*600f14f4SXin Li /******************************************************************************
48*600f14f4SXin Li 	The general strategy of these tests (for interface levels 1 and 2) is
49*600f14f4SXin Li 	to create a dummy FLAC file with a known set of initial metadata
50*600f14f4SXin Li 	blocks, then keep a mirror locally of what we expect the metadata to be
51*600f14f4SXin Li 	after each operation.  Then testing becomes a simple matter of running
52*600f14f4SXin Li 	a FLAC__StreamDecoder over the dummy file after each operation, comparing
53*600f14f4SXin Li 	the decoded metadata to what's in our local copy.  If there are any
54*600f14f4SXin Li 	differences in the metadata, or the actual audio data is corrupted, we
55*600f14f4SXin Li 	will catch it while decoding.
56*600f14f4SXin Li ******************************************************************************/
57*600f14f4SXin Li 
58*600f14f4SXin Li typedef struct {
59*600f14f4SXin Li 	FLAC__bool error_occurred;
60*600f14f4SXin Li } decoder_client_struct;
61*600f14f4SXin Li 
62*600f14f4SXin Li typedef struct {
63*600f14f4SXin Li 	FLAC__StreamMetadata *blocks[64];
64*600f14f4SXin Li 	uint32_t num_blocks;
65*600f14f4SXin Li } our_metadata_struct;
66*600f14f4SXin Li 
67*600f14f4SXin Li /* our copy of the metadata in flacfilename() */
68*600f14f4SXin Li static our_metadata_struct our_metadata_;
69*600f14f4SXin Li 
70*600f14f4SXin Li /* the current block number that corresponds to the position of the iterator we are testing */
71*600f14f4SXin Li static uint32_t mc_our_block_number_ = 0;
72*600f14f4SXin Li 
flacfilename(FLAC__bool is_ogg)73*600f14f4SXin Li static const char *flacfilename(FLAC__bool is_ogg)
74*600f14f4SXin Li {
75*600f14f4SXin Li 	return is_ogg? "metadata.oga" : "metadata.flac";
76*600f14f4SXin Li }
77*600f14f4SXin Li 
die_(const char * msg)78*600f14f4SXin Li static FLAC__bool die_(const char *msg)
79*600f14f4SXin Li {
80*600f14f4SXin Li 	printf("ERROR: %s\n", msg);
81*600f14f4SXin Li 	return false;
82*600f14f4SXin Li }
83*600f14f4SXin Li 
die_c_(const char * msg,FLAC__Metadata_ChainStatus status)84*600f14f4SXin Li static FLAC__bool die_c_(const char *msg, FLAC__Metadata_ChainStatus status)
85*600f14f4SXin Li {
86*600f14f4SXin Li 	printf("ERROR: %s\n", msg);
87*600f14f4SXin Li 	printf("       status=%s\n", FLAC__Metadata_ChainStatusString[status]);
88*600f14f4SXin Li 	return false;
89*600f14f4SXin Li }
90*600f14f4SXin Li 
die_ss_(const char * msg,FLAC__Metadata_SimpleIterator * iterator)91*600f14f4SXin Li static FLAC__bool die_ss_(const char *msg, FLAC__Metadata_SimpleIterator *iterator)
92*600f14f4SXin Li {
93*600f14f4SXin Li 	printf("ERROR: %s\n", msg);
94*600f14f4SXin Li 	printf("       status=%s\n", FLAC__Metadata_SimpleIteratorStatusString[FLAC__metadata_simple_iterator_status(iterator)]);
95*600f14f4SXin Li 	return false;
96*600f14f4SXin Li }
97*600f14f4SXin Li 
malloc_or_die_(size_t size)98*600f14f4SXin Li static void *malloc_or_die_(size_t size)
99*600f14f4SXin Li {
100*600f14f4SXin Li 	void *x = malloc(size);
101*600f14f4SXin Li 	if(0 == x) {
102*600f14f4SXin Li 		fprintf(stderr, "ERROR: out of memory allocating %u bytes\n", (uint32_t)size);
103*600f14f4SXin Li 		exit(1);
104*600f14f4SXin Li 	}
105*600f14f4SXin Li 	return x;
106*600f14f4SXin Li }
107*600f14f4SXin Li 
strdup_or_die_(const char * s)108*600f14f4SXin Li static char *strdup_or_die_(const char *s)
109*600f14f4SXin Li {
110*600f14f4SXin Li 	char *x = strdup(s);
111*600f14f4SXin Li 	if(0 == x) {
112*600f14f4SXin Li 		fprintf(stderr, "ERROR: out of memory copying string \"%s\"\n", s);
113*600f14f4SXin Li 		exit(1);
114*600f14f4SXin Li 	}
115*600f14f4SXin Li 	return x;
116*600f14f4SXin Li }
117*600f14f4SXin Li 
118*600f14f4SXin Li /* functions for working with our metadata copy */
119*600f14f4SXin Li 
replace_in_our_metadata_(FLAC__StreamMetadata * block,uint32_t position,FLAC__bool copy)120*600f14f4SXin Li static FLAC__bool replace_in_our_metadata_(FLAC__StreamMetadata *block, uint32_t position, FLAC__bool copy)
121*600f14f4SXin Li {
122*600f14f4SXin Li 	uint32_t i;
123*600f14f4SXin Li 	FLAC__StreamMetadata *obj = block;
124*600f14f4SXin Li 	FLAC__ASSERT(position < our_metadata_.num_blocks);
125*600f14f4SXin Li 	if(copy) {
126*600f14f4SXin Li 		if(0 == (obj = FLAC__metadata_object_clone(block)))
127*600f14f4SXin Li 			return die_("during FLAC__metadata_object_clone()");
128*600f14f4SXin Li 	}
129*600f14f4SXin Li 	FLAC__metadata_object_delete(our_metadata_.blocks[position]);
130*600f14f4SXin Li 	our_metadata_.blocks[position] = obj;
131*600f14f4SXin Li 
132*600f14f4SXin Li 	/* set the is_last flags */
133*600f14f4SXin Li 	for(i = 0; i < our_metadata_.num_blocks - 1; i++)
134*600f14f4SXin Li 		our_metadata_.blocks[i]->is_last = false;
135*600f14f4SXin Li 	our_metadata_.blocks[i]->is_last = true;
136*600f14f4SXin Li 
137*600f14f4SXin Li 	return true;
138*600f14f4SXin Li }
139*600f14f4SXin Li 
insert_to_our_metadata_(FLAC__StreamMetadata * block,uint32_t position,FLAC__bool copy)140*600f14f4SXin Li static FLAC__bool insert_to_our_metadata_(FLAC__StreamMetadata *block, uint32_t position, FLAC__bool copy)
141*600f14f4SXin Li {
142*600f14f4SXin Li 	uint32_t i;
143*600f14f4SXin Li 	FLAC__StreamMetadata *obj = block;
144*600f14f4SXin Li 	if(copy) {
145*600f14f4SXin Li 		if(0 == (obj = FLAC__metadata_object_clone(block)))
146*600f14f4SXin Li 			return die_("during FLAC__metadata_object_clone()");
147*600f14f4SXin Li 	}
148*600f14f4SXin Li 	if(position > our_metadata_.num_blocks) {
149*600f14f4SXin Li 		position = our_metadata_.num_blocks;
150*600f14f4SXin Li 	}
151*600f14f4SXin Li 	else {
152*600f14f4SXin Li 		for(i = our_metadata_.num_blocks; i > position; i--)
153*600f14f4SXin Li 			our_metadata_.blocks[i] = our_metadata_.blocks[i-1];
154*600f14f4SXin Li 	}
155*600f14f4SXin Li 	our_metadata_.blocks[position] = obj;
156*600f14f4SXin Li 	our_metadata_.num_blocks++;
157*600f14f4SXin Li 
158*600f14f4SXin Li 	/* set the is_last flags */
159*600f14f4SXin Li 	for(i = 0; i < our_metadata_.num_blocks - 1; i++)
160*600f14f4SXin Li 		our_metadata_.blocks[i]->is_last = false;
161*600f14f4SXin Li 	our_metadata_.blocks[i]->is_last = true;
162*600f14f4SXin Li 
163*600f14f4SXin Li 	return true;
164*600f14f4SXin Li }
165*600f14f4SXin Li 
delete_from_our_metadata_(uint32_t position)166*600f14f4SXin Li static void delete_from_our_metadata_(uint32_t position)
167*600f14f4SXin Li {
168*600f14f4SXin Li 	uint32_t i;
169*600f14f4SXin Li 	FLAC__ASSERT(position < our_metadata_.num_blocks);
170*600f14f4SXin Li 	FLAC__metadata_object_delete(our_metadata_.blocks[position]);
171*600f14f4SXin Li 	for(i = position; i < our_metadata_.num_blocks - 1; i++)
172*600f14f4SXin Li 		our_metadata_.blocks[i] = our_metadata_.blocks[i+1];
173*600f14f4SXin Li 	our_metadata_.num_blocks--;
174*600f14f4SXin Li 
175*600f14f4SXin Li 	/* set the is_last flags */
176*600f14f4SXin Li 	if(our_metadata_.num_blocks > 0) {
177*600f14f4SXin Li 		for(i = 0; i < our_metadata_.num_blocks - 1; i++)
178*600f14f4SXin Li 			our_metadata_.blocks[i]->is_last = false;
179*600f14f4SXin Li 		our_metadata_.blocks[i]->is_last = true;
180*600f14f4SXin Li 	}
181*600f14f4SXin Li }
182*600f14f4SXin Li 
183*600f14f4SXin Li /*
184*600f14f4SXin Li  * This wad of functions supports filename- and callback-based chain reading/writing.
185*600f14f4SXin Li  * Everything up to set_file_stats_() is copied from libFLAC/metadata_iterators.c
186*600f14f4SXin Li  */
open_tempfile_(const char * filename,FILE ** tempfile,char ** tempfilename)187*600f14f4SXin Li static FLAC__bool open_tempfile_(const char *filename, FILE **tempfile, char **tempfilename)
188*600f14f4SXin Li {
189*600f14f4SXin Li 	static const char *tempfile_suffix = ".metadata_edit";
190*600f14f4SXin Li 	size_t dest_len = strlen(filename) + strlen(tempfile_suffix) + 1;
191*600f14f4SXin Li 
192*600f14f4SXin Li 	*tempfilename = malloc(dest_len);
193*600f14f4SXin Li 	if (*tempfilename == NULL)
194*600f14f4SXin Li 		return false;
195*600f14f4SXin Li 	safe_strncpy(*tempfilename, filename, dest_len);
196*600f14f4SXin Li 	safe_strncat(*tempfilename, tempfile_suffix, dest_len);
197*600f14f4SXin Li 
198*600f14f4SXin Li 	*tempfile = flac_fopen(*tempfilename, "wb");
199*600f14f4SXin Li 	if (*tempfile == NULL)
200*600f14f4SXin Li 		return false;
201*600f14f4SXin Li 
202*600f14f4SXin Li 	return true;
203*600f14f4SXin Li }
204*600f14f4SXin Li 
cleanup_tempfile_(FILE ** tempfile,char ** tempfilename)205*600f14f4SXin Li static void cleanup_tempfile_(FILE **tempfile, char **tempfilename)
206*600f14f4SXin Li {
207*600f14f4SXin Li 	if (*tempfile != NULL) {
208*600f14f4SXin Li 		(void)fclose(*tempfile);
209*600f14f4SXin Li 		*tempfile = 0;
210*600f14f4SXin Li 	}
211*600f14f4SXin Li 
212*600f14f4SXin Li 	if (*tempfilename != NULL) {
213*600f14f4SXin Li 		(void)flac_unlink(*tempfilename);
214*600f14f4SXin Li 		free(*tempfilename);
215*600f14f4SXin Li 		*tempfilename = 0;
216*600f14f4SXin Li 	}
217*600f14f4SXin Li }
218*600f14f4SXin Li 
transport_tempfile_(const char * filename,FILE ** tempfile,char ** tempfilename)219*600f14f4SXin Li static FLAC__bool transport_tempfile_(const char *filename, FILE **tempfile, char **tempfilename)
220*600f14f4SXin Li {
221*600f14f4SXin Li 	FLAC__ASSERT(0 != filename);
222*600f14f4SXin Li 	FLAC__ASSERT(0 != tempfile);
223*600f14f4SXin Li 	FLAC__ASSERT(0 != tempfilename);
224*600f14f4SXin Li 	FLAC__ASSERT(0 != *tempfilename);
225*600f14f4SXin Li 
226*600f14f4SXin Li 	if(0 != *tempfile) {
227*600f14f4SXin Li 		(void)fclose(*tempfile);
228*600f14f4SXin Li 		*tempfile = 0;
229*600f14f4SXin Li 	}
230*600f14f4SXin Li 
231*600f14f4SXin Li #if defined _MSC_VER || defined __MINGW32__ || defined __EMX__
232*600f14f4SXin Li 	/* on some flavors of windows, flac_rename() will fail if the destination already exists */
233*600f14f4SXin Li 	if(flac_unlink(filename) < 0) {
234*600f14f4SXin Li 		cleanup_tempfile_(tempfile, tempfilename);
235*600f14f4SXin Li 		return false;
236*600f14f4SXin Li 	}
237*600f14f4SXin Li #endif
238*600f14f4SXin Li 
239*600f14f4SXin Li 	if(0 != flac_rename(*tempfilename, filename)) {
240*600f14f4SXin Li 		cleanup_tempfile_(tempfile, tempfilename);
241*600f14f4SXin Li 		return false;
242*600f14f4SXin Li 	}
243*600f14f4SXin Li 
244*600f14f4SXin Li 	cleanup_tempfile_(tempfile, tempfilename);
245*600f14f4SXin Li 
246*600f14f4SXin Li 	return true;
247*600f14f4SXin Li }
248*600f14f4SXin Li 
get_file_stats_(const char * filename,struct flac_stat_s * stats)249*600f14f4SXin Li static FLAC__bool get_file_stats_(const char *filename, struct flac_stat_s *stats)
250*600f14f4SXin Li {
251*600f14f4SXin Li 	FLAC__ASSERT(0 != filename);
252*600f14f4SXin Li 	FLAC__ASSERT(0 != stats);
253*600f14f4SXin Li 	return (0 == flac_stat(filename, stats));
254*600f14f4SXin Li }
255*600f14f4SXin Li 
set_file_stats_(const char * filename,struct flac_stat_s * stats)256*600f14f4SXin Li static void set_file_stats_(const char *filename, struct flac_stat_s *stats)
257*600f14f4SXin Li {
258*600f14f4SXin Li #if defined(_POSIX_C_SOURCE) && (_POSIX_C_SOURCE >= 200809L) && !defined(_WIN32)
259*600f14f4SXin Li 	struct timespec srctime[2] = {};
260*600f14f4SXin Li 	srctime[0].tv_sec = stats->st_atime;
261*600f14f4SXin Li 	srctime[1].tv_sec = stats->st_mtime;
262*600f14f4SXin Li #else
263*600f14f4SXin Li 	struct utimbuf srctime;
264*600f14f4SXin Li 	srctime.actime = stats->st_atime;
265*600f14f4SXin Li 	srctime.modtime = stats->st_mtime;
266*600f14f4SXin Li #endif
267*600f14f4SXin Li 	FLAC__ASSERT(0 != filename);
268*600f14f4SXin Li 	FLAC__ASSERT(0 != stats);
269*600f14f4SXin Li 
270*600f14f4SXin Li 	(void)flac_chmod(filename, stats->st_mode);
271*600f14f4SXin Li 	(void)flac_utime(filename, &srctime);
272*600f14f4SXin Li #if !defined _MSC_VER && !defined __MINGW32__
273*600f14f4SXin Li 	FLAC_CHECK_RETURN(chown(filename, stats->st_uid, -1));
274*600f14f4SXin Li 	FLAC_CHECK_RETURN(chown(filename, -1, stats->st_gid));
275*600f14f4SXin Li #endif
276*600f14f4SXin Li }
277*600f14f4SXin Li 
278*600f14f4SXin Li #ifdef FLAC__VALGRIND_TESTING
chain_write_cb_(const void * ptr,size_t size,size_t nmemb,FLAC__IOHandle handle)279*600f14f4SXin Li static size_t chain_write_cb_(const void *ptr, size_t size, size_t nmemb, FLAC__IOHandle handle)
280*600f14f4SXin Li {
281*600f14f4SXin Li 	FILE *stream = (FILE*)handle;
282*600f14f4SXin Li 	size_t ret = fwrite(ptr, size, nmemb, stream);
283*600f14f4SXin Li 	if(!ferror(stream))
284*600f14f4SXin Li 		fflush(stream);
285*600f14f4SXin Li 	return ret;
286*600f14f4SXin Li }
287*600f14f4SXin Li #endif
288*600f14f4SXin Li 
chain_seek_cb_(FLAC__IOHandle handle,FLAC__int64 offset,int whence)289*600f14f4SXin Li static int chain_seek_cb_(FLAC__IOHandle handle, FLAC__int64 offset, int whence)
290*600f14f4SXin Li {
291*600f14f4SXin Li 	FLAC__off_t o = (FLAC__off_t)offset;
292*600f14f4SXin Li 	FLAC__ASSERT(offset == o);
293*600f14f4SXin Li 	return fseeko((FILE*)handle, o, whence);
294*600f14f4SXin Li }
295*600f14f4SXin Li 
chain_tell_cb_(FLAC__IOHandle handle)296*600f14f4SXin Li static FLAC__int64 chain_tell_cb_(FLAC__IOHandle handle)
297*600f14f4SXin Li {
298*600f14f4SXin Li 	return ftello((FILE*)handle);
299*600f14f4SXin Li }
300*600f14f4SXin Li 
chain_eof_cb_(FLAC__IOHandle handle)301*600f14f4SXin Li static int chain_eof_cb_(FLAC__IOHandle handle)
302*600f14f4SXin Li {
303*600f14f4SXin Li 	return feof((FILE*)handle);
304*600f14f4SXin Li }
305*600f14f4SXin Li 
write_chain_(FLAC__Metadata_Chain * chain,FLAC__bool use_padding,FLAC__bool preserve_file_stats,FLAC__bool filename_based,const char * filename)306*600f14f4SXin Li static FLAC__bool write_chain_(FLAC__Metadata_Chain *chain, FLAC__bool use_padding, FLAC__bool preserve_file_stats, FLAC__bool filename_based, const char *filename)
307*600f14f4SXin Li {
308*600f14f4SXin Li 	if(filename_based)
309*600f14f4SXin Li 		return FLAC__metadata_chain_write(chain, use_padding, preserve_file_stats);
310*600f14f4SXin Li 	else {
311*600f14f4SXin Li 		FLAC__IOCallbacks callbacks;
312*600f14f4SXin Li 
313*600f14f4SXin Li 		memset(&callbacks, 0, sizeof(callbacks));
314*600f14f4SXin Li 		callbacks.read = (FLAC__IOCallback_Read)fread;
315*600f14f4SXin Li #ifdef FLAC__VALGRIND_TESTING
316*600f14f4SXin Li 		callbacks.write = chain_write_cb_;
317*600f14f4SXin Li #else
318*600f14f4SXin Li 		callbacks.write = (FLAC__IOCallback_Write)fwrite;
319*600f14f4SXin Li #endif
320*600f14f4SXin Li 		callbacks.seek = chain_seek_cb_;
321*600f14f4SXin Li 		callbacks.eof = chain_eof_cb_;
322*600f14f4SXin Li 
323*600f14f4SXin Li 		if(FLAC__metadata_chain_check_if_tempfile_needed(chain, use_padding)) {
324*600f14f4SXin Li 			struct flac_stat_s stats;
325*600f14f4SXin Li 			FILE *file, *tempfile = 0;
326*600f14f4SXin Li 			char *tempfilename;
327*600f14f4SXin Li 			if(preserve_file_stats) {
328*600f14f4SXin Li 				if(!get_file_stats_(filename, &stats))
329*600f14f4SXin Li 					return false;
330*600f14f4SXin Li 			}
331*600f14f4SXin Li 			if(0 == (file = flac_fopen(filename, "rb")))
332*600f14f4SXin Li 				return false; /*@@@@ chain status still says OK though */
333*600f14f4SXin Li 			if(!open_tempfile_(filename, &tempfile, &tempfilename)) {
334*600f14f4SXin Li 				fclose(file);
335*600f14f4SXin Li 				cleanup_tempfile_(&tempfile, &tempfilename);
336*600f14f4SXin Li 				return false; /*@@@@ chain status still says OK though */
337*600f14f4SXin Li 			}
338*600f14f4SXin Li 			if(!FLAC__metadata_chain_write_with_callbacks_and_tempfile(chain, use_padding, (FLAC__IOHandle)file, callbacks, (FLAC__IOHandle)tempfile, callbacks)) {
339*600f14f4SXin Li 				fclose(file);
340*600f14f4SXin Li 				fclose(tempfile);
341*600f14f4SXin Li 				return false;
342*600f14f4SXin Li 			}
343*600f14f4SXin Li 			fclose(file);
344*600f14f4SXin Li 			fclose(tempfile);
345*600f14f4SXin Li 			file = tempfile = 0;
346*600f14f4SXin Li 			if(!transport_tempfile_(filename, &tempfile, &tempfilename))
347*600f14f4SXin Li 				return false;
348*600f14f4SXin Li 			if(preserve_file_stats)
349*600f14f4SXin Li 				set_file_stats_(filename, &stats);
350*600f14f4SXin Li 		}
351*600f14f4SXin Li 		else {
352*600f14f4SXin Li 			FILE *file = flac_fopen(filename, "r+b");
353*600f14f4SXin Li 			if(0 == file)
354*600f14f4SXin Li 				return false; /*@@@@ chain status still says OK though */
355*600f14f4SXin Li 			if(!FLAC__metadata_chain_write_with_callbacks(chain, use_padding, (FLAC__IOHandle)file, callbacks))
356*600f14f4SXin Li 				return false;
357*600f14f4SXin Li 			fclose(file);
358*600f14f4SXin Li 		}
359*600f14f4SXin Li 	}
360*600f14f4SXin Li 
361*600f14f4SXin Li 	return true;
362*600f14f4SXin Li }
363*600f14f4SXin Li 
read_chain_(FLAC__Metadata_Chain * chain,const char * filename,FLAC__bool filename_based,FLAC__bool is_ogg)364*600f14f4SXin Li static FLAC__bool read_chain_(FLAC__Metadata_Chain *chain, const char *filename, FLAC__bool filename_based, FLAC__bool is_ogg)
365*600f14f4SXin Li {
366*600f14f4SXin Li 	if(filename_based)
367*600f14f4SXin Li 		return is_ogg?
368*600f14f4SXin Li 			FLAC__metadata_chain_read_ogg(chain, flacfilename(is_ogg)) :
369*600f14f4SXin Li 			FLAC__metadata_chain_read(chain, flacfilename(is_ogg))
370*600f14f4SXin Li 		;
371*600f14f4SXin Li 	else {
372*600f14f4SXin Li 		FLAC__IOCallbacks callbacks;
373*600f14f4SXin Li 
374*600f14f4SXin Li 		memset(&callbacks, 0, sizeof(callbacks));
375*600f14f4SXin Li 		callbacks.read = (FLAC__IOCallback_Read)fread;
376*600f14f4SXin Li 		callbacks.seek = chain_seek_cb_;
377*600f14f4SXin Li 		callbacks.tell = chain_tell_cb_;
378*600f14f4SXin Li 
379*600f14f4SXin Li 		{
380*600f14f4SXin Li 			FLAC__bool ret;
381*600f14f4SXin Li 			FILE *file = flac_fopen(filename, "rb");
382*600f14f4SXin Li 			if(0 == file)
383*600f14f4SXin Li 				return false; /*@@@@ chain status still says OK though */
384*600f14f4SXin Li 			ret = is_ogg?
385*600f14f4SXin Li 				FLAC__metadata_chain_read_ogg_with_callbacks(chain, (FLAC__IOHandle)file, callbacks) :
386*600f14f4SXin Li 				FLAC__metadata_chain_read_with_callbacks(chain, (FLAC__IOHandle)file, callbacks)
387*600f14f4SXin Li 			;
388*600f14f4SXin Li 			fclose(file);
389*600f14f4SXin Li 			return ret;
390*600f14f4SXin Li 		}
391*600f14f4SXin Li 	}
392*600f14f4SXin Li }
393*600f14f4SXin Li 
394*600f14f4SXin Li /* function for comparing our metadata to a FLAC__Metadata_Chain */
395*600f14f4SXin Li 
compare_chain_(FLAC__Metadata_Chain * chain,uint32_t current_position,FLAC__StreamMetadata * current_block)396*600f14f4SXin Li static FLAC__bool compare_chain_(FLAC__Metadata_Chain *chain, uint32_t current_position, FLAC__StreamMetadata *current_block)
397*600f14f4SXin Li {
398*600f14f4SXin Li 	uint32_t i;
399*600f14f4SXin Li 	FLAC__Metadata_Iterator *iterator;
400*600f14f4SXin Li 	FLAC__StreamMetadata *block;
401*600f14f4SXin Li 	FLAC__bool next_ok = true;
402*600f14f4SXin Li 
403*600f14f4SXin Li 	FLAC__ASSERT(0 != chain);
404*600f14f4SXin Li 
405*600f14f4SXin Li 	printf("\tcomparing chain... ");
406*600f14f4SXin Li 	fflush(stdout);
407*600f14f4SXin Li 
408*600f14f4SXin Li 	if(0 == (iterator = FLAC__metadata_iterator_new()))
409*600f14f4SXin Li 		return die_("allocating memory for iterator");
410*600f14f4SXin Li 
411*600f14f4SXin Li 	FLAC__metadata_iterator_init(iterator, chain);
412*600f14f4SXin Li 
413*600f14f4SXin Li 	i = 0;
414*600f14f4SXin Li 	do {
415*600f14f4SXin Li 		printf("%u... ", i);
416*600f14f4SXin Li 		fflush(stdout);
417*600f14f4SXin Li 
418*600f14f4SXin Li 		if(0 == (block = FLAC__metadata_iterator_get_block(iterator))) {
419*600f14f4SXin Li 			FLAC__metadata_iterator_delete(iterator);
420*600f14f4SXin Li 			return die_("getting block from iterator");
421*600f14f4SXin Li 		}
422*600f14f4SXin Li 
423*600f14f4SXin Li 		if(!mutils__compare_block(our_metadata_.blocks[i], block)) {
424*600f14f4SXin Li 			FLAC__metadata_iterator_delete(iterator);
425*600f14f4SXin Li 			return die_("metadata block mismatch");
426*600f14f4SXin Li 		}
427*600f14f4SXin Li 
428*600f14f4SXin Li 		i++;
429*600f14f4SXin Li 		next_ok = FLAC__metadata_iterator_next(iterator);
430*600f14f4SXin Li 	} while(i < our_metadata_.num_blocks && next_ok);
431*600f14f4SXin Li 
432*600f14f4SXin Li 	FLAC__metadata_iterator_delete(iterator);
433*600f14f4SXin Li 
434*600f14f4SXin Li 	if(next_ok)
435*600f14f4SXin Li 		return die_("chain has more blocks than expected");
436*600f14f4SXin Li 
437*600f14f4SXin Li 	if(i < our_metadata_.num_blocks)
438*600f14f4SXin Li 		return die_("short block count in chain");
439*600f14f4SXin Li 
440*600f14f4SXin Li 	if(0 != current_block) {
441*600f14f4SXin Li 		printf("CURRENT_POSITION... ");
442*600f14f4SXin Li 		fflush(stdout);
443*600f14f4SXin Li 
444*600f14f4SXin Li 		if(!mutils__compare_block(our_metadata_.blocks[current_position], current_block))
445*600f14f4SXin Li 			return die_("metadata block mismatch");
446*600f14f4SXin Li 	}
447*600f14f4SXin Li 
448*600f14f4SXin Li 	printf("PASSED\n");
449*600f14f4SXin Li 
450*600f14f4SXin Li 	return true;
451*600f14f4SXin Li }
452*600f14f4SXin Li 
453*600f14f4SXin Li /* decoder callbacks for checking the file */
454*600f14f4SXin Li 
decoder_write_callback_(const FLAC__StreamDecoder * decoder,const FLAC__Frame * frame,const FLAC__int32 * const buffer[],void * client_data)455*600f14f4SXin Li static FLAC__StreamDecoderWriteStatus decoder_write_callback_(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data)
456*600f14f4SXin Li {
457*600f14f4SXin Li 	(void)decoder, (void)buffer, (void)client_data;
458*600f14f4SXin Li 
459*600f14f4SXin Li 	if(
460*600f14f4SXin Li 		(frame->header.number_type == FLAC__FRAME_NUMBER_TYPE_FRAME_NUMBER && frame->header.number.frame_number == 0) ||
461*600f14f4SXin Li 		(frame->header.number_type == FLAC__FRAME_NUMBER_TYPE_SAMPLE_NUMBER && frame->header.number.sample_number == 0)
462*600f14f4SXin Li 	) {
463*600f14f4SXin Li 		printf("content... ");
464*600f14f4SXin Li 		fflush(stdout);
465*600f14f4SXin Li 	}
466*600f14f4SXin Li 
467*600f14f4SXin Li 	return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
468*600f14f4SXin Li }
469*600f14f4SXin Li 
470*600f14f4SXin Li /* this version pays no attention to the metadata */
decoder_metadata_callback_null_(const FLAC__StreamDecoder * decoder,const FLAC__StreamMetadata * metadata,void * client_data)471*600f14f4SXin Li static void decoder_metadata_callback_null_(const FLAC__StreamDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data)
472*600f14f4SXin Li {
473*600f14f4SXin Li 	(void)decoder, (void)metadata, (void)client_data;
474*600f14f4SXin Li 
475*600f14f4SXin Li 	printf("%u... ", mc_our_block_number_);
476*600f14f4SXin Li 	fflush(stdout);
477*600f14f4SXin Li 
478*600f14f4SXin Li 	mc_our_block_number_++;
479*600f14f4SXin Li }
480*600f14f4SXin Li 
481*600f14f4SXin Li /* this version is used when we want to compare to our metadata copy */
decoder_metadata_callback_compare_(const FLAC__StreamDecoder * decoder,const FLAC__StreamMetadata * metadata,void * client_data)482*600f14f4SXin Li static void decoder_metadata_callback_compare_(const FLAC__StreamDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data)
483*600f14f4SXin Li {
484*600f14f4SXin Li 	decoder_client_struct *dcd = (decoder_client_struct*)client_data;
485*600f14f4SXin Li 
486*600f14f4SXin Li 	(void)decoder;
487*600f14f4SXin Li 
488*600f14f4SXin Li 	/* don't bother checking if we've already hit an error */
489*600f14f4SXin Li 	if(dcd->error_occurred)
490*600f14f4SXin Li 		return;
491*600f14f4SXin Li 
492*600f14f4SXin Li 	printf("%u... ", mc_our_block_number_);
493*600f14f4SXin Li 	fflush(stdout);
494*600f14f4SXin Li 
495*600f14f4SXin Li 	if(mc_our_block_number_ >= our_metadata_.num_blocks) {
496*600f14f4SXin Li 		(void)die_("got more metadata blocks than expected");
497*600f14f4SXin Li 		dcd->error_occurred = true;
498*600f14f4SXin Li 	}
499*600f14f4SXin Li 	else {
500*600f14f4SXin Li 		if(!mutils__compare_block(our_metadata_.blocks[mc_our_block_number_], metadata)) {
501*600f14f4SXin Li 			(void)die_("metadata block mismatch");
502*600f14f4SXin Li 			dcd->error_occurred = true;
503*600f14f4SXin Li 		}
504*600f14f4SXin Li 	}
505*600f14f4SXin Li 	mc_our_block_number_++;
506*600f14f4SXin Li }
507*600f14f4SXin Li 
decoder_error_callback_(const FLAC__StreamDecoder * decoder,FLAC__StreamDecoderErrorStatus status,void * client_data)508*600f14f4SXin Li static void decoder_error_callback_(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data)
509*600f14f4SXin Li {
510*600f14f4SXin Li 	decoder_client_struct *dcd = (decoder_client_struct*)client_data;
511*600f14f4SXin Li 	(void)decoder;
512*600f14f4SXin Li 
513*600f14f4SXin Li 	dcd->error_occurred = true;
514*600f14f4SXin Li 	printf("ERROR: got error callback, status = %s (%u)\n", FLAC__StreamDecoderErrorStatusString[status], (uint32_t)status);
515*600f14f4SXin Li }
516*600f14f4SXin Li 
generate_file_(FLAC__bool include_extras,FLAC__bool is_ogg)517*600f14f4SXin Li static FLAC__bool generate_file_(FLAC__bool include_extras, FLAC__bool is_ogg)
518*600f14f4SXin Li {
519*600f14f4SXin Li 	FLAC__StreamMetadata streaminfo, vorbiscomment, *cuesheet, picture, padding;
520*600f14f4SXin Li 	FLAC__StreamMetadata *metadata[4];
521*600f14f4SXin Li 	uint32_t i = 0, n = 0;
522*600f14f4SXin Li 
523*600f14f4SXin Li 	printf("generating %sFLAC file for test\n", is_ogg? "Ogg " : "");
524*600f14f4SXin Li 
525*600f14f4SXin Li 	while(our_metadata_.num_blocks > 0)
526*600f14f4SXin Li 		delete_from_our_metadata_(0);
527*600f14f4SXin Li 
528*600f14f4SXin Li 	streaminfo.is_last = false;
529*600f14f4SXin Li 	streaminfo.type = FLAC__METADATA_TYPE_STREAMINFO;
530*600f14f4SXin Li 	streaminfo.length = FLAC__STREAM_METADATA_STREAMINFO_LENGTH;
531*600f14f4SXin Li 	streaminfo.data.stream_info.min_blocksize = 576;
532*600f14f4SXin Li 	streaminfo.data.stream_info.max_blocksize = 576;
533*600f14f4SXin Li 	streaminfo.data.stream_info.min_framesize = 0;
534*600f14f4SXin Li 	streaminfo.data.stream_info.max_framesize = 0;
535*600f14f4SXin Li 	streaminfo.data.stream_info.sample_rate = 44100;
536*600f14f4SXin Li 	streaminfo.data.stream_info.channels = 1;
537*600f14f4SXin Li 	streaminfo.data.stream_info.bits_per_sample = 8;
538*600f14f4SXin Li 	streaminfo.data.stream_info.total_samples = 0;
539*600f14f4SXin Li 	memset(streaminfo.data.stream_info.md5sum, 0, 16);
540*600f14f4SXin Li 
541*600f14f4SXin Li 	{
542*600f14f4SXin Li 		const uint32_t vendor_string_length = (uint32_t)strlen(FLAC__VENDOR_STRING);
543*600f14f4SXin Li 		vorbiscomment.is_last = false;
544*600f14f4SXin Li 		vorbiscomment.type = FLAC__METADATA_TYPE_VORBIS_COMMENT;
545*600f14f4SXin Li 		vorbiscomment.length = (4 + vendor_string_length) + 4;
546*600f14f4SXin Li 		vorbiscomment.data.vorbis_comment.vendor_string.length = vendor_string_length;
547*600f14f4SXin Li 		vorbiscomment.data.vorbis_comment.vendor_string.entry = malloc_or_die_(vendor_string_length+1);
548*600f14f4SXin Li 		memcpy(vorbiscomment.data.vorbis_comment.vendor_string.entry, FLAC__VENDOR_STRING, vendor_string_length+1);
549*600f14f4SXin Li 		vorbiscomment.data.vorbis_comment.num_comments = 0;
550*600f14f4SXin Li 		vorbiscomment.data.vorbis_comment.comments = 0;
551*600f14f4SXin Li 	}
552*600f14f4SXin Li 
553*600f14f4SXin Li 	{
554*600f14f4SXin Li 		if (0 == (cuesheet = FLAC__metadata_object_new(FLAC__METADATA_TYPE_CUESHEET)))
555*600f14f4SXin Li 			return die_("priming our metadata");
556*600f14f4SXin Li 		cuesheet->is_last = false;
557*600f14f4SXin Li 		safe_strncpy(cuesheet->data.cue_sheet.media_catalog_number, "bogo-MCN", sizeof(cuesheet->data.cue_sheet.media_catalog_number));
558*600f14f4SXin Li 		cuesheet->data.cue_sheet.lead_in = 123;
559*600f14f4SXin Li 		cuesheet->data.cue_sheet.is_cd = false;
560*600f14f4SXin Li 		if (!FLAC__metadata_object_cuesheet_insert_blank_track(cuesheet, 0))
561*600f14f4SXin Li 			return die_("priming our metadata");
562*600f14f4SXin Li 		cuesheet->data.cue_sheet.tracks[0].number = 1;
563*600f14f4SXin Li 		if (!FLAC__metadata_object_cuesheet_track_insert_blank_index(cuesheet, 0, 0))
564*600f14f4SXin Li 			return die_("priming our metadata");
565*600f14f4SXin Li 	}
566*600f14f4SXin Li 
567*600f14f4SXin Li 	{
568*600f14f4SXin Li 		picture.is_last = false;
569*600f14f4SXin Li 		picture.type = FLAC__METADATA_TYPE_PICTURE;
570*600f14f4SXin Li 		picture.length =
571*600f14f4SXin Li 			(
572*600f14f4SXin Li 				FLAC__STREAM_METADATA_PICTURE_TYPE_LEN +
573*600f14f4SXin Li 				FLAC__STREAM_METADATA_PICTURE_MIME_TYPE_LENGTH_LEN + /* will add the length for the string later */
574*600f14f4SXin Li 				FLAC__STREAM_METADATA_PICTURE_DESCRIPTION_LENGTH_LEN + /* will add the length for the string later */
575*600f14f4SXin Li 				FLAC__STREAM_METADATA_PICTURE_WIDTH_LEN +
576*600f14f4SXin Li 				FLAC__STREAM_METADATA_PICTURE_HEIGHT_LEN +
577*600f14f4SXin Li 				FLAC__STREAM_METADATA_PICTURE_DEPTH_LEN +
578*600f14f4SXin Li 				FLAC__STREAM_METADATA_PICTURE_COLORS_LEN +
579*600f14f4SXin Li 				FLAC__STREAM_METADATA_PICTURE_DATA_LENGTH_LEN /* will add the length for the data later */
580*600f14f4SXin Li 			) / 8
581*600f14f4SXin Li 		;
582*600f14f4SXin Li 		picture.data.picture.type = FLAC__STREAM_METADATA_PICTURE_TYPE_FRONT_COVER;
583*600f14f4SXin Li 		picture.data.picture.mime_type = strdup_or_die_("image/jpeg");
584*600f14f4SXin Li 		picture.length += strlen(picture.data.picture.mime_type);
585*600f14f4SXin Li 		picture.data.picture.description = (FLAC__byte*)strdup_or_die_("desc");
586*600f14f4SXin Li 		picture.length += strlen((const char *)picture.data.picture.description);
587*600f14f4SXin Li 		picture.data.picture.width = 300;
588*600f14f4SXin Li 		picture.data.picture.height = 300;
589*600f14f4SXin Li 		picture.data.picture.depth = 24;
590*600f14f4SXin Li 		picture.data.picture.colors = 0;
591*600f14f4SXin Li 		picture.data.picture.data = (FLAC__byte*)strdup_or_die_("SOMEJPEGDATA");
592*600f14f4SXin Li 		picture.data.picture.data_length = strlen((const char *)picture.data.picture.data);
593*600f14f4SXin Li 		picture.length += picture.data.picture.data_length;
594*600f14f4SXin Li 	}
595*600f14f4SXin Li 
596*600f14f4SXin Li 	padding.is_last = true;
597*600f14f4SXin Li 	padding.type = FLAC__METADATA_TYPE_PADDING;
598*600f14f4SXin Li 	padding.length = 1234;
599*600f14f4SXin Li 
600*600f14f4SXin Li 	metadata[n++] = &vorbiscomment;
601*600f14f4SXin Li 	if(include_extras) {
602*600f14f4SXin Li 		metadata[n++] = cuesheet;
603*600f14f4SXin Li 		metadata[n++] = &picture;
604*600f14f4SXin Li 	}
605*600f14f4SXin Li 	metadata[n++] = &padding;
606*600f14f4SXin Li 
607*600f14f4SXin Li 	if(
608*600f14f4SXin Li 		!insert_to_our_metadata_(&streaminfo, i++, /*copy=*/true) ||
609*600f14f4SXin Li 		!insert_to_our_metadata_(&vorbiscomment, i++, /*copy=*/true) ||
610*600f14f4SXin Li 		(include_extras && !insert_to_our_metadata_(cuesheet, i++, /*copy=*/false)) ||
611*600f14f4SXin Li 		(include_extras && !insert_to_our_metadata_(&picture, i++, /*copy=*/true)) ||
612*600f14f4SXin Li 		!insert_to_our_metadata_(&padding, i++, /*copy=*/true)
613*600f14f4SXin Li 	)
614*600f14f4SXin Li 		return die_("priming our metadata");
615*600f14f4SXin Li 
616*600f14f4SXin Li 	if(!file_utils__generate_flacfile(is_ogg, flacfilename(is_ogg), 0, 512 * 1024, &streaminfo, metadata, n))
617*600f14f4SXin Li 		return die_("creating the encoded file");
618*600f14f4SXin Li 
619*600f14f4SXin Li 	free(vorbiscomment.data.vorbis_comment.vendor_string.entry);
620*600f14f4SXin Li 	free(picture.data.picture.mime_type);
621*600f14f4SXin Li 	free(picture.data.picture.description);
622*600f14f4SXin Li 	free(picture.data.picture.data);
623*600f14f4SXin Li 	if(!include_extras)
624*600f14f4SXin Li 		FLAC__metadata_object_delete(cuesheet);
625*600f14f4SXin Li 
626*600f14f4SXin Li 	return true;
627*600f14f4SXin Li }
628*600f14f4SXin Li 
test_file_(FLAC__bool is_ogg,FLAC__StreamDecoderMetadataCallback metadata_callback)629*600f14f4SXin Li static FLAC__bool test_file_(FLAC__bool is_ogg, FLAC__StreamDecoderMetadataCallback metadata_callback)
630*600f14f4SXin Li {
631*600f14f4SXin Li 	const char *filename = flacfilename(is_ogg);
632*600f14f4SXin Li 	FLAC__StreamDecoder *decoder;
633*600f14f4SXin Li 	decoder_client_struct decoder_client_data;
634*600f14f4SXin Li 
635*600f14f4SXin Li 	FLAC__ASSERT(0 != metadata_callback);
636*600f14f4SXin Li 
637*600f14f4SXin Li 	mc_our_block_number_ = 0;
638*600f14f4SXin Li 	decoder_client_data.error_occurred = false;
639*600f14f4SXin Li 
640*600f14f4SXin Li 	printf("\ttesting '%s'... ", filename);
641*600f14f4SXin Li 	fflush(stdout);
642*600f14f4SXin Li 
643*600f14f4SXin Li 	if(0 == (decoder = FLAC__stream_decoder_new()))
644*600f14f4SXin Li 		return die_("couldn't allocate decoder instance");
645*600f14f4SXin Li 
646*600f14f4SXin Li 	FLAC__stream_decoder_set_md5_checking(decoder, true);
647*600f14f4SXin Li 	FLAC__stream_decoder_set_metadata_respond_all(decoder);
648*600f14f4SXin Li 	if(
649*600f14f4SXin Li 		(is_ogg?
650*600f14f4SXin Li 			FLAC__stream_decoder_init_ogg_file(decoder, filename, decoder_write_callback_, metadata_callback, decoder_error_callback_, &decoder_client_data) :
651*600f14f4SXin Li 			FLAC__stream_decoder_init_file(decoder, filename, decoder_write_callback_, metadata_callback, decoder_error_callback_, &decoder_client_data)
652*600f14f4SXin Li 		) != FLAC__STREAM_DECODER_INIT_STATUS_OK
653*600f14f4SXin Li 	) {
654*600f14f4SXin Li 		(void)FLAC__stream_decoder_finish(decoder);
655*600f14f4SXin Li 		FLAC__stream_decoder_delete(decoder);
656*600f14f4SXin Li 		return die_("initializing decoder\n");
657*600f14f4SXin Li 	}
658*600f14f4SXin Li 	if(!FLAC__stream_decoder_process_until_end_of_stream(decoder)) {
659*600f14f4SXin Li 		(void)FLAC__stream_decoder_finish(decoder);
660*600f14f4SXin Li 		FLAC__stream_decoder_delete(decoder);
661*600f14f4SXin Li 		return die_("decoding file\n");
662*600f14f4SXin Li 	}
663*600f14f4SXin Li 
664*600f14f4SXin Li 	(void)FLAC__stream_decoder_finish(decoder);
665*600f14f4SXin Li 	FLAC__stream_decoder_delete(decoder);
666*600f14f4SXin Li 
667*600f14f4SXin Li 	if(decoder_client_data.error_occurred)
668*600f14f4SXin Li 		return false;
669*600f14f4SXin Li 
670*600f14f4SXin Li 	if(mc_our_block_number_ != our_metadata_.num_blocks)
671*600f14f4SXin Li 		return die_("short metadata block count");
672*600f14f4SXin Li 
673*600f14f4SXin Li 	printf("PASSED\n");
674*600f14f4SXin Li 	return true;
675*600f14f4SXin Li }
676*600f14f4SXin Li 
change_stats_(const char * filename,FLAC__bool read_only)677*600f14f4SXin Li static FLAC__bool change_stats_(const char *filename, FLAC__bool read_only)
678*600f14f4SXin Li {
679*600f14f4SXin Li 	if(!grabbag__file_change_stats(filename, read_only))
680*600f14f4SXin Li 		return die_("during grabbag__file_change_stats()");
681*600f14f4SXin Li 
682*600f14f4SXin Li 	return true;
683*600f14f4SXin Li }
684*600f14f4SXin Li 
remove_file_(const char * filename)685*600f14f4SXin Li static FLAC__bool remove_file_(const char *filename)
686*600f14f4SXin Li {
687*600f14f4SXin Li 	while(our_metadata_.num_blocks > 0)
688*600f14f4SXin Li 		delete_from_our_metadata_(0);
689*600f14f4SXin Li 
690*600f14f4SXin Li 	if(!grabbag__file_remove_file(filename))
691*600f14f4SXin Li 		return die_("removing file");
692*600f14f4SXin Li 
693*600f14f4SXin Li 	return true;
694*600f14f4SXin Li }
695*600f14f4SXin Li 
test_level_0_(void)696*600f14f4SXin Li static FLAC__bool test_level_0_(void)
697*600f14f4SXin Li {
698*600f14f4SXin Li 	FLAC__StreamMetadata streaminfo;
699*600f14f4SXin Li 	FLAC__StreamMetadata *tags = 0;
700*600f14f4SXin Li 	FLAC__StreamMetadata *cuesheet = 0;
701*600f14f4SXin Li 	FLAC__StreamMetadata *picture = 0;
702*600f14f4SXin Li 
703*600f14f4SXin Li 	printf("\n\n++++++ testing level 0 interface\n");
704*600f14f4SXin Li 
705*600f14f4SXin Li 	if(!generate_file_(/*include_extras=*/true, /*is_ogg=*/false))
706*600f14f4SXin Li 		return false;
707*600f14f4SXin Li 
708*600f14f4SXin Li 	if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_null_))
709*600f14f4SXin Li 		return false;
710*600f14f4SXin Li 
711*600f14f4SXin Li 	printf("testing FLAC__metadata_get_streaminfo()... ");
712*600f14f4SXin Li 
713*600f14f4SXin Li 	if(!FLAC__metadata_get_streaminfo(flacfilename(/*is_ogg=*/false), &streaminfo))
714*600f14f4SXin Li 		return die_("during FLAC__metadata_get_streaminfo()");
715*600f14f4SXin Li 
716*600f14f4SXin Li 	/* check to see if some basic data matches (c.f. generate_file_()) */
717*600f14f4SXin Li 	if(streaminfo.data.stream_info.channels != 1)
718*600f14f4SXin Li 		return die_("mismatch in streaminfo.data.stream_info.channels");
719*600f14f4SXin Li 	if(streaminfo.data.stream_info.bits_per_sample != 8)
720*600f14f4SXin Li 		return die_("mismatch in streaminfo.data.stream_info.bits_per_sample");
721*600f14f4SXin Li 	if(streaminfo.data.stream_info.sample_rate != 44100)
722*600f14f4SXin Li 		return die_("mismatch in streaminfo.data.stream_info.sample_rate");
723*600f14f4SXin Li 	if(streaminfo.data.stream_info.min_blocksize != 576)
724*600f14f4SXin Li 		return die_("mismatch in streaminfo.data.stream_info.min_blocksize");
725*600f14f4SXin Li 	if(streaminfo.data.stream_info.max_blocksize != 576)
726*600f14f4SXin Li 		return die_("mismatch in streaminfo.data.stream_info.max_blocksize");
727*600f14f4SXin Li 
728*600f14f4SXin Li 	printf("OK\n");
729*600f14f4SXin Li 
730*600f14f4SXin Li 	printf("testing FLAC__metadata_get_tags()... ");
731*600f14f4SXin Li 
732*600f14f4SXin Li 	if(!FLAC__metadata_get_tags(flacfilename(/*is_ogg=*/false), &tags))
733*600f14f4SXin Li 		return die_("during FLAC__metadata_get_tags()");
734*600f14f4SXin Li 
735*600f14f4SXin Li 	/* check to see if some basic data matches (c.f. generate_file_()) */
736*600f14f4SXin Li 	if(tags->data.vorbis_comment.num_comments != 0)
737*600f14f4SXin Li 		return die_("mismatch in tags->data.vorbis_comment.num_comments");
738*600f14f4SXin Li 
739*600f14f4SXin Li 	printf("OK\n");
740*600f14f4SXin Li 
741*600f14f4SXin Li 	FLAC__metadata_object_delete(tags);
742*600f14f4SXin Li 
743*600f14f4SXin Li 	printf("testing FLAC__metadata_get_cuesheet()... ");
744*600f14f4SXin Li 
745*600f14f4SXin Li 	if(!FLAC__metadata_get_cuesheet(flacfilename(/*is_ogg=*/false), &cuesheet))
746*600f14f4SXin Li 		return die_("during FLAC__metadata_get_cuesheet()");
747*600f14f4SXin Li 
748*600f14f4SXin Li 	/* check to see if some basic data matches (c.f. generate_file_()) */
749*600f14f4SXin Li 	if(cuesheet->data.cue_sheet.lead_in != 123)
750*600f14f4SXin Li 		return die_("mismatch in cuesheet->data.cue_sheet.lead_in");
751*600f14f4SXin Li 
752*600f14f4SXin Li 	printf("OK\n");
753*600f14f4SXin Li 
754*600f14f4SXin Li 	FLAC__metadata_object_delete(cuesheet);
755*600f14f4SXin Li 
756*600f14f4SXin Li 	printf("testing FLAC__metadata_get_picture()... ");
757*600f14f4SXin Li 
758*600f14f4SXin Li 	if(!FLAC__metadata_get_picture(flacfilename(/*is_ogg=*/false), &picture, /*type=*/(FLAC__StreamMetadata_Picture_Type)(-1), /*mime_type=*/0, /*description=*/0, /*max_width=*/(uint32_t)(-1), /*max_height=*/(uint32_t)(-1), /*max_depth=*/(uint32_t)(-1), /*max_colors=*/(uint32_t)(-1)))
759*600f14f4SXin Li 		return die_("during FLAC__metadata_get_picture()");
760*600f14f4SXin Li 
761*600f14f4SXin Li 	/* check to see if some basic data matches (c.f. generate_file_()) */
762*600f14f4SXin Li 	if(picture->data.picture.type != FLAC__STREAM_METADATA_PICTURE_TYPE_FRONT_COVER)
763*600f14f4SXin Li 		return die_("mismatch in picture->data.picture.type");
764*600f14f4SXin Li 
765*600f14f4SXin Li 	printf("OK\n");
766*600f14f4SXin Li 
767*600f14f4SXin Li 	FLAC__metadata_object_delete(picture);
768*600f14f4SXin Li 
769*600f14f4SXin Li 	if(!remove_file_(flacfilename(/*is_ogg=*/false)))
770*600f14f4SXin Li 		return false;
771*600f14f4SXin Li 
772*600f14f4SXin Li 	return true;
773*600f14f4SXin Li }
774*600f14f4SXin Li 
test_level_1_(void)775*600f14f4SXin Li static FLAC__bool test_level_1_(void)
776*600f14f4SXin Li {
777*600f14f4SXin Li 	FLAC__Metadata_SimpleIterator *iterator;
778*600f14f4SXin Li 	FLAC__StreamMetadata *block, *app, *padding;
779*600f14f4SXin Li 	FLAC__byte data[1000];
780*600f14f4SXin Li 	uint32_t our_current_position = 0;
781*600f14f4SXin Li 
782*600f14f4SXin Li 	/* initialize 'data' to avoid Valgrind errors */
783*600f14f4SXin Li 	memset(data, 0, sizeof(data));
784*600f14f4SXin Li 
785*600f14f4SXin Li 	printf("\n\n++++++ testing level 1 interface\n");
786*600f14f4SXin Li 
787*600f14f4SXin Li 	/************************************************************/
788*600f14f4SXin Li 
789*600f14f4SXin Li 	printf("simple iterator on read-only file\n");
790*600f14f4SXin Li 
791*600f14f4SXin Li 	if(!generate_file_(/*include_extras=*/false, /*is_ogg=*/false))
792*600f14f4SXin Li 		return false;
793*600f14f4SXin Li 
794*600f14f4SXin Li 	if(!change_stats_(flacfilename(/*is_ogg=*/false), /*read_only=*/true))
795*600f14f4SXin Li 		return false;
796*600f14f4SXin Li 
797*600f14f4SXin Li 	if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_null_))
798*600f14f4SXin Li 		return false;
799*600f14f4SXin Li 
800*600f14f4SXin Li 	if(0 == (iterator = FLAC__metadata_simple_iterator_new()))
801*600f14f4SXin Li 		return die_("FLAC__metadata_simple_iterator_new()");
802*600f14f4SXin Li 
803*600f14f4SXin Li 	if(!FLAC__metadata_simple_iterator_init(iterator, flacfilename(/*is_ogg=*/false), /*read_only=*/false, /*preserve_file_stats=*/false))
804*600f14f4SXin Li 		return die_("FLAC__metadata_simple_iterator_init() returned false");
805*600f14f4SXin Li 
806*600f14f4SXin Li 	printf("is writable = %u\n", (uint32_t)FLAC__metadata_simple_iterator_is_writable(iterator));
807*600f14f4SXin Li 	if(FLAC__metadata_simple_iterator_is_writable(iterator))
808*600f14f4SXin Li 		return die_("iterator claims file is writable when tester thinks it should not be; are you running as root?\n");
809*600f14f4SXin Li 
810*600f14f4SXin Li 	printf("iterate forwards\n");
811*600f14f4SXin Li 
812*600f14f4SXin Li 	if(FLAC__metadata_simple_iterator_get_block_type(iterator) != FLAC__METADATA_TYPE_STREAMINFO)
813*600f14f4SXin Li 		return die_("expected STREAMINFO type from FLAC__metadata_simple_iterator_get_block_type()");
814*600f14f4SXin Li 	if(0 == (block = FLAC__metadata_simple_iterator_get_block(iterator)))
815*600f14f4SXin Li 		return die_("getting block 0");
816*600f14f4SXin Li 	if(block->type != FLAC__METADATA_TYPE_STREAMINFO)
817*600f14f4SXin Li 		return die_("expected STREAMINFO type");
818*600f14f4SXin Li 	if(block->is_last)
819*600f14f4SXin Li 		return die_("expected is_last to be false");
820*600f14f4SXin Li 	if(block->length != FLAC__STREAM_METADATA_STREAMINFO_LENGTH)
821*600f14f4SXin Li 		return die_("bad STREAMINFO length");
822*600f14f4SXin Li 	/* check to see if some basic data matches (c.f. generate_file_()) */
823*600f14f4SXin Li 	if(block->data.stream_info.channels != 1)
824*600f14f4SXin Li 		return die_("mismatch in channels");
825*600f14f4SXin Li 	if(block->data.stream_info.bits_per_sample != 8)
826*600f14f4SXin Li 		return die_("mismatch in bits_per_sample");
827*600f14f4SXin Li 	if(block->data.stream_info.sample_rate != 44100)
828*600f14f4SXin Li 		return die_("mismatch in sample_rate");
829*600f14f4SXin Li 	if(block->data.stream_info.min_blocksize != 576)
830*600f14f4SXin Li 		return die_("mismatch in min_blocksize");
831*600f14f4SXin Li 	if(block->data.stream_info.max_blocksize != 576)
832*600f14f4SXin Li 		return die_("mismatch in max_blocksize");
833*600f14f4SXin Li 	FLAC__metadata_object_delete(block);
834*600f14f4SXin Li 
835*600f14f4SXin Li 	if(!FLAC__metadata_simple_iterator_next(iterator))
836*600f14f4SXin Li 		return die_("forward iterator ended early");
837*600f14f4SXin Li 	our_current_position++;
838*600f14f4SXin Li 
839*600f14f4SXin Li 	if(!FLAC__metadata_simple_iterator_next(iterator))
840*600f14f4SXin Li 		return die_("forward iterator ended early");
841*600f14f4SXin Li 	our_current_position++;
842*600f14f4SXin Li 
843*600f14f4SXin Li 	if(FLAC__metadata_simple_iterator_get_block_type(iterator) != FLAC__METADATA_TYPE_PADDING)
844*600f14f4SXin Li 		return die_("expected PADDING type from FLAC__metadata_simple_iterator_get_block_type()");
845*600f14f4SXin Li 	if(0 == (block = FLAC__metadata_simple_iterator_get_block(iterator)))
846*600f14f4SXin Li 		return die_("getting block 2");
847*600f14f4SXin Li 	if(block->type != FLAC__METADATA_TYPE_PADDING)
848*600f14f4SXin Li 		return die_("expected PADDING type");
849*600f14f4SXin Li 	if(!block->is_last)
850*600f14f4SXin Li 		return die_("expected is_last to be true");
851*600f14f4SXin Li 	/* check to see if some basic data matches (c.f. generate_file_()) */
852*600f14f4SXin Li 	if(block->length != 1234)
853*600f14f4SXin Li 		return die_("bad PADDING length");
854*600f14f4SXin Li 	FLAC__metadata_object_delete(block);
855*600f14f4SXin Li 
856*600f14f4SXin Li 	if(FLAC__metadata_simple_iterator_next(iterator))
857*600f14f4SXin Li 		return die_("forward iterator returned true but should have returned false");
858*600f14f4SXin Li 
859*600f14f4SXin Li 	printf("iterate backwards\n");
860*600f14f4SXin Li 	if(!FLAC__metadata_simple_iterator_prev(iterator))
861*600f14f4SXin Li 		return die_("reverse iterator ended early");
862*600f14f4SXin Li 	if(!FLAC__metadata_simple_iterator_prev(iterator))
863*600f14f4SXin Li 		return die_("reverse iterator ended early");
864*600f14f4SXin Li 	if(FLAC__metadata_simple_iterator_prev(iterator))
865*600f14f4SXin Li 		return die_("reverse iterator returned true but should have returned false");
866*600f14f4SXin Li 
867*600f14f4SXin Li 	printf("testing FLAC__metadata_simple_iterator_set_block() on read-only file...\n");
868*600f14f4SXin Li 
869*600f14f4SXin Li 	if(!FLAC__metadata_simple_iterator_set_block(iterator, (FLAC__StreamMetadata*)99, false))
870*600f14f4SXin Li 		printf("OK: FLAC__metadata_simple_iterator_set_block() returned false like it should\n");
871*600f14f4SXin Li 	else
872*600f14f4SXin Li 		return die_("FLAC__metadata_simple_iterator_set_block() returned true but shouldn't have");
873*600f14f4SXin Li 
874*600f14f4SXin Li 	FLAC__metadata_simple_iterator_delete(iterator);
875*600f14f4SXin Li 
876*600f14f4SXin Li 	/************************************************************/
877*600f14f4SXin Li 
878*600f14f4SXin Li 	printf("simple iterator on writable file\n");
879*600f14f4SXin Li 
880*600f14f4SXin Li 	if(!change_stats_(flacfilename(/*is_ogg=*/false), /*read-only=*/false))
881*600f14f4SXin Li 		return false;
882*600f14f4SXin Li 
883*600f14f4SXin Li 	printf("creating APPLICATION block\n");
884*600f14f4SXin Li 
885*600f14f4SXin Li 	if(0 == (app = FLAC__metadata_object_new(FLAC__METADATA_TYPE_APPLICATION)))
886*600f14f4SXin Li 		return die_("FLAC__metadata_object_new(FLAC__METADATA_TYPE_APPLICATION)");
887*600f14f4SXin Li 	memcpy(app->data.application.id, "duh", (FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8));
888*600f14f4SXin Li 
889*600f14f4SXin Li 	printf("creating PADDING block\n");
890*600f14f4SXin Li 
891*600f14f4SXin Li 	if(0 == (padding = FLAC__metadata_object_new(FLAC__METADATA_TYPE_PADDING)))
892*600f14f4SXin Li 		return die_("FLAC__metadata_object_new(FLAC__METADATA_TYPE_PADDING)");
893*600f14f4SXin Li 	padding->length = 20;
894*600f14f4SXin Li 
895*600f14f4SXin Li 	if(0 == (iterator = FLAC__metadata_simple_iterator_new()))
896*600f14f4SXin Li 		return die_("FLAC__metadata_simple_iterator_new()");
897*600f14f4SXin Li 
898*600f14f4SXin Li 	if(!FLAC__metadata_simple_iterator_init(iterator, flacfilename(/*is_ogg=*/false), /*read_only=*/false, /*preserve_file_stats=*/false))
899*600f14f4SXin Li 		return die_("FLAC__metadata_simple_iterator_init() returned false");
900*600f14f4SXin Li 	our_current_position = 0;
901*600f14f4SXin Li 
902*600f14f4SXin Li 	printf("is writable = %u\n", (uint32_t)FLAC__metadata_simple_iterator_is_writable(iterator));
903*600f14f4SXin Li 
904*600f14f4SXin Li 	printf("[S]VP\ttry to write over STREAMINFO block...\n");
905*600f14f4SXin Li 	if(!FLAC__metadata_simple_iterator_set_block(iterator, app, false))
906*600f14f4SXin Li 		printf("\tFLAC__metadata_simple_iterator_set_block() returned false like it should\n");
907*600f14f4SXin Li 	else
908*600f14f4SXin Li 		return die_("FLAC__metadata_simple_iterator_set_block() returned true but shouldn't have");
909*600f14f4SXin Li 
910*600f14f4SXin Li 	if(FLAC__metadata_simple_iterator_status(iterator) != FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ILLEGAL_INPUT)
911*600f14f4SXin Li 		return die_("FLAC__metadata_simple_iterator_status() should have been FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ILLEGAL_INPUT");
912*600f14f4SXin Li 
913*600f14f4SXin Li 	printf("[S]VP\tnext\n");
914*600f14f4SXin Li 	if(!FLAC__metadata_simple_iterator_next(iterator))
915*600f14f4SXin Li 		return die_("iterator ended early\n");
916*600f14f4SXin Li 	our_current_position++;
917*600f14f4SXin Li 
918*600f14f4SXin Li 	printf("S[V]P\tnext\n");
919*600f14f4SXin Li 	if(!FLAC__metadata_simple_iterator_next(iterator))
920*600f14f4SXin Li 		return die_("iterator ended early\n");
921*600f14f4SXin Li 	our_current_position++;
922*600f14f4SXin Li 
923*600f14f4SXin Li 	printf("SV[P]\tinsert PADDING after, don't expand into padding\n");
924*600f14f4SXin Li 	padding->length = 25;
925*600f14f4SXin Li 	if(!FLAC__metadata_simple_iterator_insert_block_after(iterator, padding, false))
926*600f14f4SXin Li 		return die_ss_("FLAC__metadata_simple_iterator_insert_block_after(iterator, padding, false)", iterator);
927*600f14f4SXin Li 	if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
928*600f14f4SXin Li 		return false;
929*600f14f4SXin Li 
930*600f14f4SXin Li 	printf("SVP[P]\tprev\n");
931*600f14f4SXin Li 	if(!FLAC__metadata_simple_iterator_prev(iterator))
932*600f14f4SXin Li 		return die_("iterator ended early\n");
933*600f14f4SXin Li 	our_current_position--;
934*600f14f4SXin Li 
935*600f14f4SXin Li 	printf("SV[P]P\tprev\n");
936*600f14f4SXin Li 	if(!FLAC__metadata_simple_iterator_prev(iterator))
937*600f14f4SXin Li 		return die_("iterator ended early\n");
938*600f14f4SXin Li 	our_current_position--;
939*600f14f4SXin Li 
940*600f14f4SXin Li 	printf("S[V]PP\tinsert PADDING after, don't expand into padding\n");
941*600f14f4SXin Li 	padding->length = 30;
942*600f14f4SXin Li 	if(!FLAC__metadata_simple_iterator_insert_block_after(iterator, padding, false))
943*600f14f4SXin Li 		return die_ss_("FLAC__metadata_simple_iterator_insert_block_after(iterator, padding, false)", iterator);
944*600f14f4SXin Li 	if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
945*600f14f4SXin Li 		return false;
946*600f14f4SXin Li 
947*600f14f4SXin Li 	if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
948*600f14f4SXin Li 		return false;
949*600f14f4SXin Li 
950*600f14f4SXin Li 	printf("SV[P]PP\tprev\n");
951*600f14f4SXin Li 	if(!FLAC__metadata_simple_iterator_prev(iterator))
952*600f14f4SXin Li 		return die_("iterator ended early\n");
953*600f14f4SXin Li 	our_current_position--;
954*600f14f4SXin Li 
955*600f14f4SXin Li 	printf("S[V]PPP\tprev\n");
956*600f14f4SXin Li 	if(!FLAC__metadata_simple_iterator_prev(iterator))
957*600f14f4SXin Li 		return die_("iterator ended early\n");
958*600f14f4SXin Li 	our_current_position--;
959*600f14f4SXin Li 
960*600f14f4SXin Li 	printf("[S]VPPP\tdelete (STREAMINFO block), must fail\n");
961*600f14f4SXin Li 	if(FLAC__metadata_simple_iterator_delete_block(iterator, false))
962*600f14f4SXin Li 		return die_ss_("FLAC__metadata_simple_iterator_delete_block(iterator, false) should have returned false", iterator);
963*600f14f4SXin Li 
964*600f14f4SXin Li 	if(FLAC__metadata_simple_iterator_status(iterator) != FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ILLEGAL_INPUT)
965*600f14f4SXin Li 		return die_("FLAC__metadata_simple_iterator_status() should have been FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ILLEGAL_INPUT");
966*600f14f4SXin Li 
967*600f14f4SXin Li 	if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
968*600f14f4SXin Li 		return false;
969*600f14f4SXin Li 
970*600f14f4SXin Li 	printf("[S]VPPP\tnext\n");
971*600f14f4SXin Li 	if(!FLAC__metadata_simple_iterator_next(iterator))
972*600f14f4SXin Li 		return die_("iterator ended early\n");
973*600f14f4SXin Li 	our_current_position++;
974*600f14f4SXin Li 
975*600f14f4SXin Li 	printf("S[V]PPP\tnext\n");
976*600f14f4SXin Li 	if(!FLAC__metadata_simple_iterator_next(iterator))
977*600f14f4SXin Li 		return die_("iterator ended early\n");
978*600f14f4SXin Li 	our_current_position++;
979*600f14f4SXin Li 
980*600f14f4SXin Li 	printf("SV[P]PP\tdelete (middle block), replace with padding\n");
981*600f14f4SXin Li 	if(!FLAC__metadata_simple_iterator_delete_block(iterator, true))
982*600f14f4SXin Li 		return die_ss_("FLAC__metadata_simple_iterator_delete_block(iterator, true)", iterator);
983*600f14f4SXin Li 	our_current_position--;
984*600f14f4SXin Li 
985*600f14f4SXin Li 	printf("S[V]PPP\tnext\n");
986*600f14f4SXin Li 	if(!FLAC__metadata_simple_iterator_next(iterator))
987*600f14f4SXin Li 		return die_("iterator ended early\n");
988*600f14f4SXin Li 	our_current_position++;
989*600f14f4SXin Li 
990*600f14f4SXin Li 	printf("SV[P]PP\tdelete (middle block), don't replace with padding\n");
991*600f14f4SXin Li 	if(!FLAC__metadata_simple_iterator_delete_block(iterator, false))
992*600f14f4SXin Li 		return die_ss_("FLAC__metadata_simple_iterator_delete_block(iterator, false)", iterator);
993*600f14f4SXin Li 	delete_from_our_metadata_(our_current_position--);
994*600f14f4SXin Li 
995*600f14f4SXin Li 	if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
996*600f14f4SXin Li 		return false;
997*600f14f4SXin Li 
998*600f14f4SXin Li 	printf("S[V]PP\tnext\n");
999*600f14f4SXin Li 	if(!FLAC__metadata_simple_iterator_next(iterator))
1000*600f14f4SXin Li 		return die_("iterator ended early\n");
1001*600f14f4SXin Li 	our_current_position++;
1002*600f14f4SXin Li 
1003*600f14f4SXin Li 	printf("SV[P]P\tnext\n");
1004*600f14f4SXin Li 	if(!FLAC__metadata_simple_iterator_next(iterator))
1005*600f14f4SXin Li 		return die_("iterator ended early\n");
1006*600f14f4SXin Li 	our_current_position++;
1007*600f14f4SXin Li 
1008*600f14f4SXin Li 	printf("SVP[P]\tdelete (last block), replace with padding\n");
1009*600f14f4SXin Li 	if(!FLAC__metadata_simple_iterator_delete_block(iterator, true))
1010*600f14f4SXin Li 		return die_ss_("FLAC__metadata_simple_iterator_delete_block(iterator, false)", iterator);
1011*600f14f4SXin Li 	our_current_position--;
1012*600f14f4SXin Li 
1013*600f14f4SXin Li 	if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
1014*600f14f4SXin Li 		return false;
1015*600f14f4SXin Li 
1016*600f14f4SXin Li 	printf("SV[P]P\tnext\n");
1017*600f14f4SXin Li 	if(!FLAC__metadata_simple_iterator_next(iterator))
1018*600f14f4SXin Li 		return die_("iterator ended early\n");
1019*600f14f4SXin Li 	our_current_position++;
1020*600f14f4SXin Li 
1021*600f14f4SXin Li 	printf("SVP[P]\tdelete (last block), don't replace with padding\n");
1022*600f14f4SXin Li 	if(!FLAC__metadata_simple_iterator_delete_block(iterator, false))
1023*600f14f4SXin Li 		return die_ss_("FLAC__metadata_simple_iterator_delete_block(iterator, false)", iterator);
1024*600f14f4SXin Li 	delete_from_our_metadata_(our_current_position--);
1025*600f14f4SXin Li 
1026*600f14f4SXin Li 	if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
1027*600f14f4SXin Li 		return false;
1028*600f14f4SXin Li 
1029*600f14f4SXin Li 	printf("SV[P]\tprev\n");
1030*600f14f4SXin Li 	if(!FLAC__metadata_simple_iterator_prev(iterator))
1031*600f14f4SXin Li 		return die_("iterator ended early\n");
1032*600f14f4SXin Li 	our_current_position--;
1033*600f14f4SXin Li 
1034*600f14f4SXin Li 	printf("S[V]P\tprev\n");
1035*600f14f4SXin Li 	if(!FLAC__metadata_simple_iterator_prev(iterator))
1036*600f14f4SXin Li 		return die_("iterator ended early\n");
1037*600f14f4SXin Li 	our_current_position--;
1038*600f14f4SXin Li 
1039*600f14f4SXin Li 	printf("[S]VP\tset STREAMINFO (change sample rate)\n");
1040*600f14f4SXin Li 	FLAC__ASSERT(our_current_position == 0);
1041*600f14f4SXin Li 	block = FLAC__metadata_simple_iterator_get_block(iterator);
1042*600f14f4SXin Li 	block->data.stream_info.sample_rate = 32000;
1043*600f14f4SXin Li 	if(!replace_in_our_metadata_(block, our_current_position, /*copy=*/true))
1044*600f14f4SXin Li 		return die_("copying object");
1045*600f14f4SXin Li 	if(!FLAC__metadata_simple_iterator_set_block(iterator, block, false))
1046*600f14f4SXin Li 		return die_ss_("FLAC__metadata_simple_iterator_set_block(iterator, block, false)", iterator);
1047*600f14f4SXin Li 	FLAC__metadata_object_delete(block);
1048*600f14f4SXin Li 
1049*600f14f4SXin Li 	if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
1050*600f14f4SXin Li 		return false;
1051*600f14f4SXin Li 
1052*600f14f4SXin Li 	printf("[S]VP\tnext\n");
1053*600f14f4SXin Li 	if(!FLAC__metadata_simple_iterator_next(iterator))
1054*600f14f4SXin Li 		return die_("iterator ended early\n");
1055*600f14f4SXin Li 	our_current_position++;
1056*600f14f4SXin Li 
1057*600f14f4SXin Li 	printf("S[V]P\tinsert APPLICATION after, expand into padding of exceeding size\n");
1058*600f14f4SXin Li 	app->data.application.id[0] = 'e'; /* twiddle the id so that our comparison doesn't miss transposition */
1059*600f14f4SXin Li 	if(!FLAC__metadata_simple_iterator_insert_block_after(iterator, app, true))
1060*600f14f4SXin Li 		return die_ss_("FLAC__metadata_simple_iterator_insert_block_after(iterator, app, true)", iterator);
1061*600f14f4SXin Li 	if(!insert_to_our_metadata_(app, ++our_current_position, /*copy=*/true))
1062*600f14f4SXin Li 		return false;
1063*600f14f4SXin Li 	our_metadata_.blocks[our_current_position+1]->length -= (FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8) + app->length;
1064*600f14f4SXin Li 
1065*600f14f4SXin Li 	if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
1066*600f14f4SXin Li 		return false;
1067*600f14f4SXin Li 
1068*600f14f4SXin Li 	printf("SV[A]P\tnext\n");
1069*600f14f4SXin Li 	if(!FLAC__metadata_simple_iterator_next(iterator))
1070*600f14f4SXin Li 		return die_("iterator ended early\n");
1071*600f14f4SXin Li 	our_current_position++;
1072*600f14f4SXin Li 
1073*600f14f4SXin Li 	printf("SVA[P]\tset APPLICATION, expand into padding of exceeding size\n");
1074*600f14f4SXin Li 	app->data.application.id[0] = 'f'; /* twiddle the id */
1075*600f14f4SXin Li 	if(!FLAC__metadata_simple_iterator_set_block(iterator, app, true))
1076*600f14f4SXin Li 		return die_ss_("FLAC__metadata_simple_iterator_set_block(iterator, app, true)", iterator);
1077*600f14f4SXin Li 	if(!insert_to_our_metadata_(app, our_current_position, /*copy=*/true))
1078*600f14f4SXin Li 		return false;
1079*600f14f4SXin Li 	our_metadata_.blocks[our_current_position+1]->length -= (FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8) + app->length;
1080*600f14f4SXin Li 
1081*600f14f4SXin Li 	if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
1082*600f14f4SXin Li 		return false;
1083*600f14f4SXin Li 
1084*600f14f4SXin Li 	printf("SVA[A]P\tset APPLICATION (grow), don't expand into padding\n");
1085*600f14f4SXin Li 	app->data.application.id[0] = 'g'; /* twiddle the id */
1086*600f14f4SXin Li 	if(!FLAC__metadata_object_application_set_data(app, data, sizeof(data), true))
1087*600f14f4SXin Li 		return die_("setting APPLICATION data");
1088*600f14f4SXin Li 	if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1089*600f14f4SXin Li 		return die_("copying object");
1090*600f14f4SXin Li 	if(!FLAC__metadata_simple_iterator_set_block(iterator, app, false))
1091*600f14f4SXin Li 		return die_ss_("FLAC__metadata_simple_iterator_set_block(iterator, app, false)", iterator);
1092*600f14f4SXin Li 
1093*600f14f4SXin Li 	if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
1094*600f14f4SXin Li 		return false;
1095*600f14f4SXin Li 
1096*600f14f4SXin Li 	printf("SVA[A]P\tset APPLICATION (shrink), don't fill in with padding\n");
1097*600f14f4SXin Li 	app->data.application.id[0] = 'h'; /* twiddle the id */
1098*600f14f4SXin Li 	if(!FLAC__metadata_object_application_set_data(app, data, 12, true))
1099*600f14f4SXin Li 		return die_("setting APPLICATION data");
1100*600f14f4SXin Li 	if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1101*600f14f4SXin Li 		return die_("copying object");
1102*600f14f4SXin Li 	if(!FLAC__metadata_simple_iterator_set_block(iterator, app, false))
1103*600f14f4SXin Li 		return die_ss_("FLAC__metadata_simple_iterator_set_block(iterator, app, false)", iterator);
1104*600f14f4SXin Li 
1105*600f14f4SXin Li 	if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
1106*600f14f4SXin Li 		return false;
1107*600f14f4SXin Li 
1108*600f14f4SXin Li 	printf("SVA[A]P\tset APPLICATION (grow), expand into padding of exceeding size\n");
1109*600f14f4SXin Li 	app->data.application.id[0] = 'i'; /* twiddle the id */
1110*600f14f4SXin Li 	if(!FLAC__metadata_object_application_set_data(app, data, sizeof(data), true))
1111*600f14f4SXin Li 		return die_("setting APPLICATION data");
1112*600f14f4SXin Li 	if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1113*600f14f4SXin Li 		return die_("copying object");
1114*600f14f4SXin Li 	our_metadata_.blocks[our_current_position+1]->length -= (sizeof(data) - 12);
1115*600f14f4SXin Li 	if(!FLAC__metadata_simple_iterator_set_block(iterator, app, true))
1116*600f14f4SXin Li 		return die_ss_("FLAC__metadata_simple_iterator_set_block(iterator, app, true)", iterator);
1117*600f14f4SXin Li 
1118*600f14f4SXin Li 	if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
1119*600f14f4SXin Li 		return false;
1120*600f14f4SXin Li 
1121*600f14f4SXin Li 	printf("SVA[A]P\tset APPLICATION (shrink), fill in with padding\n");
1122*600f14f4SXin Li 	app->data.application.id[0] = 'j'; /* twiddle the id */
1123*600f14f4SXin Li 	if(!FLAC__metadata_object_application_set_data(app, data, 23, true))
1124*600f14f4SXin Li 		return die_("setting APPLICATION data");
1125*600f14f4SXin Li 	if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1126*600f14f4SXin Li 		return die_("copying object");
1127*600f14f4SXin Li 	if(!insert_to_our_metadata_(padding, our_current_position+1, /*copy=*/true))
1128*600f14f4SXin Li 		return die_("copying object");
1129*600f14f4SXin Li 	our_metadata_.blocks[our_current_position+1]->length = sizeof(data) - 23 - FLAC__STREAM_METADATA_HEADER_LENGTH;
1130*600f14f4SXin Li 	if(!FLAC__metadata_simple_iterator_set_block(iterator, app, true))
1131*600f14f4SXin Li 		return die_ss_("FLAC__metadata_simple_iterator_set_block(iterator, app, true)", iterator);
1132*600f14f4SXin Li 
1133*600f14f4SXin Li 	if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
1134*600f14f4SXin Li 		return false;
1135*600f14f4SXin Li 
1136*600f14f4SXin Li 	printf("SVA[A]PP\tnext\n");
1137*600f14f4SXin Li 	if(!FLAC__metadata_simple_iterator_next(iterator))
1138*600f14f4SXin Li 		return die_("iterator ended early\n");
1139*600f14f4SXin Li 	our_current_position++;
1140*600f14f4SXin Li 
1141*600f14f4SXin Li 	printf("SVAA[P]P\tnext\n");
1142*600f14f4SXin Li 	if(!FLAC__metadata_simple_iterator_next(iterator))
1143*600f14f4SXin Li 		return die_("iterator ended early\n");
1144*600f14f4SXin Li 	our_current_position++;
1145*600f14f4SXin Li 
1146*600f14f4SXin Li 	printf("SVAAP[P]\tset PADDING (shrink), don't fill in with padding\n");
1147*600f14f4SXin Li 	padding->length = 5;
1148*600f14f4SXin Li 	if(!replace_in_our_metadata_(padding, our_current_position, /*copy=*/true))
1149*600f14f4SXin Li 		return die_("copying object");
1150*600f14f4SXin Li 	if(!FLAC__metadata_simple_iterator_set_block(iterator, padding, false))
1151*600f14f4SXin Li 		return die_ss_("FLAC__metadata_simple_iterator_set_block(iterator, padding, false)", iterator);
1152*600f14f4SXin Li 
1153*600f14f4SXin Li 	if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
1154*600f14f4SXin Li 		return false;
1155*600f14f4SXin Li 
1156*600f14f4SXin Li 	printf("SVAAP[P]\tset APPLICATION (grow)\n");
1157*600f14f4SXin Li 	app->data.application.id[0] = 'k'; /* twiddle the id */
1158*600f14f4SXin Li 	if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1159*600f14f4SXin Li 		return die_("copying object");
1160*600f14f4SXin Li 	if(!FLAC__metadata_simple_iterator_set_block(iterator, app, false))
1161*600f14f4SXin Li 		return die_ss_("FLAC__metadata_simple_iterator_set_block(iterator, app, false)", iterator);
1162*600f14f4SXin Li 
1163*600f14f4SXin Li 	if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
1164*600f14f4SXin Li 		return false;
1165*600f14f4SXin Li 
1166*600f14f4SXin Li 	printf("SVAAP[A]\tset PADDING (equal)\n");
1167*600f14f4SXin Li 	padding->length = 27;
1168*600f14f4SXin Li 	if(!replace_in_our_metadata_(padding, our_current_position, /*copy=*/true))
1169*600f14f4SXin Li 		return die_("copying object");
1170*600f14f4SXin Li 	if(!FLAC__metadata_simple_iterator_set_block(iterator, padding, false))
1171*600f14f4SXin Li 		return die_ss_("FLAC__metadata_simple_iterator_set_block(iterator, padding, false)", iterator);
1172*600f14f4SXin Li 
1173*600f14f4SXin Li 	if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
1174*600f14f4SXin Li 		return false;
1175*600f14f4SXin Li 
1176*600f14f4SXin Li 	printf("SVAAP[P]\tprev\n");
1177*600f14f4SXin Li 	if(!FLAC__metadata_simple_iterator_prev(iterator))
1178*600f14f4SXin Li 		return die_("iterator ended early\n");
1179*600f14f4SXin Li 	our_current_position--;
1180*600f14f4SXin Li 
1181*600f14f4SXin Li 	printf("SVAA[P]P\tdelete (middle block), don't replace with padding\n");
1182*600f14f4SXin Li 	if(!FLAC__metadata_simple_iterator_delete_block(iterator, false))
1183*600f14f4SXin Li 		return die_ss_("FLAC__metadata_simple_iterator_delete_block(iterator, false)", iterator);
1184*600f14f4SXin Li 	delete_from_our_metadata_(our_current_position--);
1185*600f14f4SXin Li 
1186*600f14f4SXin Li 	if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
1187*600f14f4SXin Li 		return false;
1188*600f14f4SXin Li 
1189*600f14f4SXin Li 	printf("SVA[A]P\tdelete (middle block), don't replace with padding\n");
1190*600f14f4SXin Li 	if(!FLAC__metadata_simple_iterator_delete_block(iterator, false))
1191*600f14f4SXin Li 		return die_ss_("FLAC__metadata_simple_iterator_delete_block(iterator, false)", iterator);
1192*600f14f4SXin Li 	delete_from_our_metadata_(our_current_position--);
1193*600f14f4SXin Li 
1194*600f14f4SXin Li 	if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
1195*600f14f4SXin Li 		return false;
1196*600f14f4SXin Li 
1197*600f14f4SXin Li 	printf("SV[A]P\tnext\n");
1198*600f14f4SXin Li 	if(!FLAC__metadata_simple_iterator_next(iterator))
1199*600f14f4SXin Li 		return die_("iterator ended early\n");
1200*600f14f4SXin Li 	our_current_position++;
1201*600f14f4SXin Li 
1202*600f14f4SXin Li 	printf("SVA[P]\tinsert PADDING after\n");
1203*600f14f4SXin Li 	padding->length = 5;
1204*600f14f4SXin Li 	if(!FLAC__metadata_simple_iterator_insert_block_after(iterator, padding, false))
1205*600f14f4SXin Li 		return die_ss_("FLAC__metadata_simple_iterator_insert_block_after(iterator, padding, false)", iterator);
1206*600f14f4SXin Li 	if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
1207*600f14f4SXin Li 		return false;
1208*600f14f4SXin Li 
1209*600f14f4SXin Li 	if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
1210*600f14f4SXin Li 		return false;
1211*600f14f4SXin Li 
1212*600f14f4SXin Li 	printf("SVAP[P]\tprev\n");
1213*600f14f4SXin Li 	if(!FLAC__metadata_simple_iterator_prev(iterator))
1214*600f14f4SXin Li 		return die_("iterator ended early\n");
1215*600f14f4SXin Li 	our_current_position--;
1216*600f14f4SXin Li 
1217*600f14f4SXin Li 	printf("SVA[P]P\tprev\n");
1218*600f14f4SXin Li 	if(!FLAC__metadata_simple_iterator_prev(iterator))
1219*600f14f4SXin Li 		return die_("iterator ended early\n");
1220*600f14f4SXin Li 	our_current_position--;
1221*600f14f4SXin Li 
1222*600f14f4SXin Li 	printf("SV[A]PP\tset APPLICATION (grow), try to expand into padding which is too small\n");
1223*600f14f4SXin Li 	if(!FLAC__metadata_object_application_set_data(app, data, 32, true))
1224*600f14f4SXin Li 		return die_("setting APPLICATION data");
1225*600f14f4SXin Li 	if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1226*600f14f4SXin Li 		return die_("copying object");
1227*600f14f4SXin Li 	if(!FLAC__metadata_simple_iterator_set_block(iterator, app, true))
1228*600f14f4SXin Li 		return die_ss_("FLAC__metadata_simple_iterator_set_block(iterator, app, true)", iterator);
1229*600f14f4SXin Li 
1230*600f14f4SXin Li 	if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
1231*600f14f4SXin Li 		return false;
1232*600f14f4SXin Li 
1233*600f14f4SXin Li 	printf("SV[A]PP\tset APPLICATION (grow), try to expand into padding which is 'close' but still too small\n");
1234*600f14f4SXin Li 	if(!FLAC__metadata_object_application_set_data(app, data, 60, true))
1235*600f14f4SXin Li 		return die_("setting APPLICATION data");
1236*600f14f4SXin Li 	if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1237*600f14f4SXin Li 		return die_("copying object");
1238*600f14f4SXin Li 	if(!FLAC__metadata_simple_iterator_set_block(iterator, app, true))
1239*600f14f4SXin Li 		return die_ss_("FLAC__metadata_simple_iterator_set_block(iterator, app, true)", iterator);
1240*600f14f4SXin Li 
1241*600f14f4SXin Li 	if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
1242*600f14f4SXin Li 		return false;
1243*600f14f4SXin Li 
1244*600f14f4SXin Li 	printf("SV[A]PP\tset APPLICATION (grow), expand into padding which will leave 0-length pad\n");
1245*600f14f4SXin Li 	if(!FLAC__metadata_object_application_set_data(app, data, 87, true))
1246*600f14f4SXin Li 		return die_("setting APPLICATION data");
1247*600f14f4SXin Li 	if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1248*600f14f4SXin Li 		return die_("copying object");
1249*600f14f4SXin Li 	our_metadata_.blocks[our_current_position+1]->length = 0;
1250*600f14f4SXin Li 	if(!FLAC__metadata_simple_iterator_set_block(iterator, app, true))
1251*600f14f4SXin Li 		return die_ss_("FLAC__metadata_simple_iterator_set_block(iterator, app, true)", iterator);
1252*600f14f4SXin Li 
1253*600f14f4SXin Li 	if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
1254*600f14f4SXin Li 		return false;
1255*600f14f4SXin Li 
1256*600f14f4SXin Li 	printf("SV[A]PP\tset APPLICATION (grow), expand into padding which is exactly consumed\n");
1257*600f14f4SXin Li 	if(!FLAC__metadata_object_application_set_data(app, data, 91, true))
1258*600f14f4SXin Li 		return die_("setting APPLICATION data");
1259*600f14f4SXin Li 	if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1260*600f14f4SXin Li 		return die_("copying object");
1261*600f14f4SXin Li 	delete_from_our_metadata_(our_current_position+1);
1262*600f14f4SXin Li 	if(!FLAC__metadata_simple_iterator_set_block(iterator, app, true))
1263*600f14f4SXin Li 		return die_ss_("FLAC__metadata_simple_iterator_set_block(iterator, app, true)", iterator);
1264*600f14f4SXin Li 
1265*600f14f4SXin Li 	if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
1266*600f14f4SXin Li 		return false;
1267*600f14f4SXin Li 
1268*600f14f4SXin Li 	printf("SV[A]P\tset APPLICATION (grow), expand into padding which is exactly consumed\n");
1269*600f14f4SXin Li 	if(!FLAC__metadata_object_application_set_data(app, data, 100, true))
1270*600f14f4SXin Li 		return die_("setting APPLICATION data");
1271*600f14f4SXin Li 	if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1272*600f14f4SXin Li 		return die_("copying object");
1273*600f14f4SXin Li 	delete_from_our_metadata_(our_current_position+1);
1274*600f14f4SXin Li 	our_metadata_.blocks[our_current_position]->is_last = true;
1275*600f14f4SXin Li 	if(!FLAC__metadata_simple_iterator_set_block(iterator, app, true))
1276*600f14f4SXin Li 		return die_ss_("FLAC__metadata_simple_iterator_set_block(iterator, app, true)", iterator);
1277*600f14f4SXin Li 
1278*600f14f4SXin Li 	if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
1279*600f14f4SXin Li 		return false;
1280*600f14f4SXin Li 
1281*600f14f4SXin Li 	printf("SV[A]\tset PADDING (equal size)\n");
1282*600f14f4SXin Li 	padding->length = app->length;
1283*600f14f4SXin Li 	if(!replace_in_our_metadata_(padding, our_current_position, /*copy=*/true))
1284*600f14f4SXin Li 		return die_("copying object");
1285*600f14f4SXin Li 	if(!FLAC__metadata_simple_iterator_set_block(iterator, padding, true))
1286*600f14f4SXin Li 		return die_ss_("FLAC__metadata_simple_iterator_set_block(iterator, padding, true)", iterator);
1287*600f14f4SXin Li 
1288*600f14f4SXin Li 	if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
1289*600f14f4SXin Li 		return false;
1290*600f14f4SXin Li 
1291*600f14f4SXin Li 	printf("SV[P]\tinsert PADDING after\n");
1292*600f14f4SXin Li 	if(!FLAC__metadata_simple_iterator_insert_block_after(iterator, padding, false))
1293*600f14f4SXin Li 		return die_ss_("FLAC__metadata_simple_iterator_insert_block_after(iterator, padding, false)", iterator);
1294*600f14f4SXin Li 	if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
1295*600f14f4SXin Li 		return false;
1296*600f14f4SXin Li 
1297*600f14f4SXin Li 	if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
1298*600f14f4SXin Li 		return false;
1299*600f14f4SXin Li 
1300*600f14f4SXin Li 	printf("SVP[P]\tinsert PADDING after\n");
1301*600f14f4SXin Li 	padding->length = 5;
1302*600f14f4SXin Li 	if(!FLAC__metadata_simple_iterator_insert_block_after(iterator, padding, false))
1303*600f14f4SXin Li 		return die_ss_("FLAC__metadata_simple_iterator_insert_block_after(iterator, padding, false)", iterator);
1304*600f14f4SXin Li 	if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
1305*600f14f4SXin Li 		return false;
1306*600f14f4SXin Li 
1307*600f14f4SXin Li 	if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
1308*600f14f4SXin Li 		return false;
1309*600f14f4SXin Li 
1310*600f14f4SXin Li 	printf("SVPP[P]\tprev\n");
1311*600f14f4SXin Li 	if(!FLAC__metadata_simple_iterator_prev(iterator))
1312*600f14f4SXin Li 		return die_("iterator ended early\n");
1313*600f14f4SXin Li 	our_current_position--;
1314*600f14f4SXin Li 
1315*600f14f4SXin Li 	printf("SVP[P]P\tprev\n");
1316*600f14f4SXin Li 	if(!FLAC__metadata_simple_iterator_prev(iterator))
1317*600f14f4SXin Li 		return die_("iterator ended early\n");
1318*600f14f4SXin Li 	our_current_position--;
1319*600f14f4SXin Li 
1320*600f14f4SXin Li 	printf("SV[P]PP\tprev\n");
1321*600f14f4SXin Li 	if(!FLAC__metadata_simple_iterator_prev(iterator))
1322*600f14f4SXin Li 		return die_("iterator ended early\n");
1323*600f14f4SXin Li 	our_current_position--;
1324*600f14f4SXin Li 
1325*600f14f4SXin Li 	printf("S[V]PPP\tinsert APPLICATION after, try to expand into padding which is too small\n");
1326*600f14f4SXin Li 	if(!FLAC__metadata_object_application_set_data(app, data, 101, true))
1327*600f14f4SXin Li 		return die_("setting APPLICATION data");
1328*600f14f4SXin Li 	if(!insert_to_our_metadata_(app, ++our_current_position, /*copy=*/true))
1329*600f14f4SXin Li 		return die_("copying object");
1330*600f14f4SXin Li 	if(!FLAC__metadata_simple_iterator_insert_block_after(iterator, app, true))
1331*600f14f4SXin Li 		return die_ss_("FLAC__metadata_simple_iterator_insert_block_after(iterator, app, true)", iterator);
1332*600f14f4SXin Li 
1333*600f14f4SXin Li 	if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
1334*600f14f4SXin Li 		return false;
1335*600f14f4SXin Li 
1336*600f14f4SXin Li 	printf("SV[A]PPP\tdelete (middle block), don't replace with padding\n");
1337*600f14f4SXin Li 	if(!FLAC__metadata_simple_iterator_delete_block(iterator, false))
1338*600f14f4SXin Li 		return die_ss_("FLAC__metadata_simple_iterator_delete_block(iterator, false)", iterator);
1339*600f14f4SXin Li 	delete_from_our_metadata_(our_current_position--);
1340*600f14f4SXin Li 
1341*600f14f4SXin Li 	if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
1342*600f14f4SXin Li 		return false;
1343*600f14f4SXin Li 
1344*600f14f4SXin Li 	printf("S[V]PPP\tinsert APPLICATION after, try to expand into padding which is 'close' but still too small\n");
1345*600f14f4SXin Li 	if(!FLAC__metadata_object_application_set_data(app, data, 97, true))
1346*600f14f4SXin Li 		return die_("setting APPLICATION data");
1347*600f14f4SXin Li 	if(!insert_to_our_metadata_(app, ++our_current_position, /*copy=*/true))
1348*600f14f4SXin Li 		return die_("copying object");
1349*600f14f4SXin Li 	if(!FLAC__metadata_simple_iterator_insert_block_after(iterator, app, true))
1350*600f14f4SXin Li 		return die_ss_("FLAC__metadata_simple_iterator_insert_block_after(iterator, app, true)", iterator);
1351*600f14f4SXin Li 
1352*600f14f4SXin Li 	if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
1353*600f14f4SXin Li 		return false;
1354*600f14f4SXin Li 
1355*600f14f4SXin Li 	printf("SV[A]PPP\tdelete (middle block), don't replace with padding\n");
1356*600f14f4SXin Li 	if(!FLAC__metadata_simple_iterator_delete_block(iterator, false))
1357*600f14f4SXin Li 		return die_ss_("FLAC__metadata_simple_iterator_delete_block(iterator, false)", iterator);
1358*600f14f4SXin Li 	delete_from_our_metadata_(our_current_position--);
1359*600f14f4SXin Li 
1360*600f14f4SXin Li 	if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
1361*600f14f4SXin Li 		return false;
1362*600f14f4SXin Li 
1363*600f14f4SXin Li 	printf("S[V]PPP\tinsert APPLICATION after, expand into padding which is exactly consumed\n");
1364*600f14f4SXin Li 	if(!FLAC__metadata_object_application_set_data(app, data, 100, true))
1365*600f14f4SXin Li 		return die_("setting APPLICATION data");
1366*600f14f4SXin Li 	if(!insert_to_our_metadata_(app, ++our_current_position, /*copy=*/true))
1367*600f14f4SXin Li 		return die_("copying object");
1368*600f14f4SXin Li 	delete_from_our_metadata_(our_current_position+1);
1369*600f14f4SXin Li 	if(!FLAC__metadata_simple_iterator_insert_block_after(iterator, app, true))
1370*600f14f4SXin Li 		return die_ss_("FLAC__metadata_simple_iterator_insert_block_after(iterator, app, true)", iterator);
1371*600f14f4SXin Li 
1372*600f14f4SXin Li 	if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
1373*600f14f4SXin Li 		return false;
1374*600f14f4SXin Li 
1375*600f14f4SXin Li 	printf("SV[A]PP\tdelete (middle block), don't replace with padding\n");
1376*600f14f4SXin Li 	if(!FLAC__metadata_simple_iterator_delete_block(iterator, false))
1377*600f14f4SXin Li 		return die_ss_("FLAC__metadata_simple_iterator_delete_block(iterator, false)", iterator);
1378*600f14f4SXin Li 	delete_from_our_metadata_(our_current_position--);
1379*600f14f4SXin Li 
1380*600f14f4SXin Li 	if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
1381*600f14f4SXin Li 		return false;
1382*600f14f4SXin Li 
1383*600f14f4SXin Li 	printf("S[V]PP\tinsert APPLICATION after, expand into padding which will leave 0-length pad\n");
1384*600f14f4SXin Li 	if(!FLAC__metadata_object_application_set_data(app, data, 96, true))
1385*600f14f4SXin Li 		return die_("setting APPLICATION data");
1386*600f14f4SXin Li 	if(!insert_to_our_metadata_(app, ++our_current_position, /*copy=*/true))
1387*600f14f4SXin Li 		return die_("copying object");
1388*600f14f4SXin Li 	our_metadata_.blocks[our_current_position+1]->length = 0;
1389*600f14f4SXin Li 	if(!FLAC__metadata_simple_iterator_insert_block_after(iterator, app, true))
1390*600f14f4SXin Li 		return die_ss_("FLAC__metadata_simple_iterator_insert_block_after(iterator, app, true)", iterator);
1391*600f14f4SXin Li 
1392*600f14f4SXin Li 	if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
1393*600f14f4SXin Li 		return false;
1394*600f14f4SXin Li 
1395*600f14f4SXin Li 	printf("SV[A]PP\tdelete (middle block), don't replace with padding\n");
1396*600f14f4SXin Li 	if(!FLAC__metadata_simple_iterator_delete_block(iterator, false))
1397*600f14f4SXin Li 		return die_ss_("FLAC__metadata_simple_iterator_delete_block(iterator, false)", iterator);
1398*600f14f4SXin Li 	delete_from_our_metadata_(our_current_position--);
1399*600f14f4SXin Li 
1400*600f14f4SXin Li 	if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
1401*600f14f4SXin Li 		return false;
1402*600f14f4SXin Li 
1403*600f14f4SXin Li 	printf("S[V]PP\tnext\n");
1404*600f14f4SXin Li 	if(!FLAC__metadata_simple_iterator_next(iterator))
1405*600f14f4SXin Li 		return die_("iterator ended early\n");
1406*600f14f4SXin Li 	our_current_position++;
1407*600f14f4SXin Li 
1408*600f14f4SXin Li 	printf("SV[P]P\tdelete (middle block), don't replace with padding\n");
1409*600f14f4SXin Li 	if(!FLAC__metadata_simple_iterator_delete_block(iterator, false))
1410*600f14f4SXin Li 		return die_ss_("FLAC__metadata_simple_iterator_delete_block(iterator, false)", iterator);
1411*600f14f4SXin Li 	delete_from_our_metadata_(our_current_position--);
1412*600f14f4SXin Li 
1413*600f14f4SXin Li 	if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
1414*600f14f4SXin Li 		return false;
1415*600f14f4SXin Li 
1416*600f14f4SXin Li 	printf("S[V]P\tinsert APPLICATION after, expand into padding which is exactly consumed\n");
1417*600f14f4SXin Li 	if(!FLAC__metadata_object_application_set_data(app, data, 1, true))
1418*600f14f4SXin Li 		return die_("setting APPLICATION data");
1419*600f14f4SXin Li 	if(!insert_to_our_metadata_(app, ++our_current_position, /*copy=*/true))
1420*600f14f4SXin Li 		return die_("copying object");
1421*600f14f4SXin Li 	delete_from_our_metadata_(our_current_position+1);
1422*600f14f4SXin Li 	if(!FLAC__metadata_simple_iterator_insert_block_after(iterator, app, true))
1423*600f14f4SXin Li 		return die_ss_("FLAC__metadata_simple_iterator_insert_block_after(iterator, app, true)", iterator);
1424*600f14f4SXin Li 
1425*600f14f4SXin Li 	if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
1426*600f14f4SXin Li 		return false;
1427*600f14f4SXin Li 
1428*600f14f4SXin Li 	printf("delete simple iterator\n");
1429*600f14f4SXin Li 
1430*600f14f4SXin Li 	FLAC__metadata_simple_iterator_delete(iterator);
1431*600f14f4SXin Li 
1432*600f14f4SXin Li 	FLAC__metadata_object_delete(app);
1433*600f14f4SXin Li 	FLAC__metadata_object_delete(padding);
1434*600f14f4SXin Li 
1435*600f14f4SXin Li 	if(!remove_file_(flacfilename(/*is_ogg=*/false)))
1436*600f14f4SXin Li 		return false;
1437*600f14f4SXin Li 
1438*600f14f4SXin Li 	return true;
1439*600f14f4SXin Li }
1440*600f14f4SXin Li 
test_level_2_(FLAC__bool filename_based,FLAC__bool is_ogg)1441*600f14f4SXin Li static FLAC__bool test_level_2_(FLAC__bool filename_based, FLAC__bool is_ogg)
1442*600f14f4SXin Li {
1443*600f14f4SXin Li 	FLAC__Metadata_Iterator *iterator;
1444*600f14f4SXin Li 	FLAC__Metadata_Chain *chain;
1445*600f14f4SXin Li 	FLAC__StreamMetadata *block, *app, *padding;
1446*600f14f4SXin Li 	FLAC__byte data[2000];
1447*600f14f4SXin Li 	uint32_t our_current_position;
1448*600f14f4SXin Li 
1449*600f14f4SXin Li 	/* initialize 'data' to avoid Valgrind errors */
1450*600f14f4SXin Li 	memset(data, 0, sizeof(data));
1451*600f14f4SXin Li 
1452*600f14f4SXin Li 	printf("\n\n++++++ testing level 2 interface (%s-based, %s FLAC)\n", filename_based? "filename":"callback", is_ogg? "Ogg":"native");
1453*600f14f4SXin Li 
1454*600f14f4SXin Li 	printf("generate read-only file\n");
1455*600f14f4SXin Li 
1456*600f14f4SXin Li 	if(!generate_file_(/*include_extras=*/false, is_ogg))
1457*600f14f4SXin Li 		return false;
1458*600f14f4SXin Li 
1459*600f14f4SXin Li 	if(!change_stats_(flacfilename(is_ogg), /*read_only=*/true))
1460*600f14f4SXin Li 		return false;
1461*600f14f4SXin Li 
1462*600f14f4SXin Li 	printf("create chain\n");
1463*600f14f4SXin Li 
1464*600f14f4SXin Li 	if(0 == (chain = FLAC__metadata_chain_new()))
1465*600f14f4SXin Li 		return die_("allocating chain");
1466*600f14f4SXin Li 
1467*600f14f4SXin Li 	printf("read chain\n");
1468*600f14f4SXin Li 
1469*600f14f4SXin Li 	if(!read_chain_(chain, flacfilename(is_ogg), filename_based, is_ogg))
1470*600f14f4SXin Li 		return die_c_("reading chain", FLAC__metadata_chain_status(chain));
1471*600f14f4SXin Li 
1472*600f14f4SXin Li 	printf("[S]VP\ttest initial metadata\n");
1473*600f14f4SXin Li 
1474*600f14f4SXin Li 	if(!compare_chain_(chain, 0, 0))
1475*600f14f4SXin Li 		return false;
1476*600f14f4SXin Li 	if(!test_file_(is_ogg, decoder_metadata_callback_compare_))
1477*600f14f4SXin Li 		return false;
1478*600f14f4SXin Li 
1479*600f14f4SXin Li 	if(is_ogg)
1480*600f14f4SXin Li 		goto end;
1481*600f14f4SXin Li 
1482*600f14f4SXin Li 	printf("switch file to read-write\n");
1483*600f14f4SXin Li 
1484*600f14f4SXin Li 	if(!change_stats_(flacfilename(is_ogg), /*read-only=*/false))
1485*600f14f4SXin Li 		return false;
1486*600f14f4SXin Li 
1487*600f14f4SXin Li 	printf("create iterator\n");
1488*600f14f4SXin Li 	if(0 == (iterator = FLAC__metadata_iterator_new()))
1489*600f14f4SXin Li 		return die_("allocating memory for iterator");
1490*600f14f4SXin Li 
1491*600f14f4SXin Li 	our_current_position = 0;
1492*600f14f4SXin Li 
1493*600f14f4SXin Li 	FLAC__metadata_iterator_init(iterator, chain);
1494*600f14f4SXin Li 
1495*600f14f4SXin Li 	if(0 == (block = FLAC__metadata_iterator_get_block(iterator)))
1496*600f14f4SXin Li 		return die_("getting block from iterator");
1497*600f14f4SXin Li 
1498*600f14f4SXin Li 	FLAC__ASSERT(block->type == FLAC__METADATA_TYPE_STREAMINFO);
1499*600f14f4SXin Li 
1500*600f14f4SXin Li 	printf("[S]VP\tmodify STREAMINFO, write\n");
1501*600f14f4SXin Li 
1502*600f14f4SXin Li 	block->data.stream_info.sample_rate = 32000;
1503*600f14f4SXin Li 	if(!replace_in_our_metadata_(block, our_current_position, /*copy=*/true))
1504*600f14f4SXin Li 		return die_("copying object");
1505*600f14f4SXin Li 
1506*600f14f4SXin Li 	if(!write_chain_(chain, /*use_padding=*/false, /*preserve_file_stats=*/true, filename_based, flacfilename(is_ogg)))
1507*600f14f4SXin Li 		return die_c_("during FLAC__metadata_chain_write(chain, false, true)", FLAC__metadata_chain_status(chain));
1508*600f14f4SXin Li 	if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
1509*600f14f4SXin Li 		return false;
1510*600f14f4SXin Li 	if(!test_file_(is_ogg, decoder_metadata_callback_compare_))
1511*600f14f4SXin Li 		return false;
1512*600f14f4SXin Li 
1513*600f14f4SXin Li 	printf("[S]VP\tnext\n");
1514*600f14f4SXin Li 	if(!FLAC__metadata_iterator_next(iterator))
1515*600f14f4SXin Li 		return die_("iterator ended early\n");
1516*600f14f4SXin Li 	our_current_position++;
1517*600f14f4SXin Li 
1518*600f14f4SXin Li 	printf("S[V]P\tnext\n");
1519*600f14f4SXin Li 	if(!FLAC__metadata_iterator_next(iterator))
1520*600f14f4SXin Li 		return die_("iterator ended early\n");
1521*600f14f4SXin Li 	our_current_position++;
1522*600f14f4SXin Li 
1523*600f14f4SXin Li 	printf("SV[P]\treplace PADDING with identical-size APPLICATION\n");
1524*600f14f4SXin Li 	if(0 == (block = FLAC__metadata_iterator_get_block(iterator)))
1525*600f14f4SXin Li 		return die_("getting block from iterator");
1526*600f14f4SXin Li 	if(0 == (app = FLAC__metadata_object_new(FLAC__METADATA_TYPE_APPLICATION)))
1527*600f14f4SXin Li 		return die_("FLAC__metadata_object_new(FLAC__METADATA_TYPE_APPLICATION)");
1528*600f14f4SXin Li 	memcpy(app->data.application.id, "duh", (FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8));
1529*600f14f4SXin Li 	if(!FLAC__metadata_object_application_set_data(app, data, block->length-(FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8), true))
1530*600f14f4SXin Li 		return die_("setting APPLICATION data");
1531*600f14f4SXin Li 	if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1532*600f14f4SXin Li 		return die_("copying object");
1533*600f14f4SXin Li 	if(!FLAC__metadata_iterator_set_block(iterator, app))
1534*600f14f4SXin Li 		return die_c_("FLAC__metadata_iterator_set_block(iterator, app)", FLAC__metadata_chain_status(chain));
1535*600f14f4SXin Li 
1536*600f14f4SXin Li 	if(!write_chain_(chain, /*use_padding=*/false, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg)))
1537*600f14f4SXin Li 		return die_c_("during FLAC__metadata_chain_write(chain, false, false)", FLAC__metadata_chain_status(chain));
1538*600f14f4SXin Li 	if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
1539*600f14f4SXin Li 		return false;
1540*600f14f4SXin Li 	if(!test_file_(is_ogg, decoder_metadata_callback_compare_))
1541*600f14f4SXin Li 		return false;
1542*600f14f4SXin Li 
1543*600f14f4SXin Li 	printf("SV[A]\tshrink APPLICATION, don't use padding\n");
1544*600f14f4SXin Li 	if(0 == (app = FLAC__metadata_object_clone(our_metadata_.blocks[our_current_position])))
1545*600f14f4SXin Li 		return die_("copying object");
1546*600f14f4SXin Li 	if(!FLAC__metadata_object_application_set_data(app, data, 26, true))
1547*600f14f4SXin Li 		return die_("setting APPLICATION data");
1548*600f14f4SXin Li 	if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1549*600f14f4SXin Li 		return die_("copying object");
1550*600f14f4SXin Li 	if(!FLAC__metadata_iterator_set_block(iterator, app))
1551*600f14f4SXin Li 		return die_c_("FLAC__metadata_iterator_set_block(iterator, app)", FLAC__metadata_chain_status(chain));
1552*600f14f4SXin Li 
1553*600f14f4SXin Li 	if(!write_chain_(chain, /*use_padding=*/false, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg)))
1554*600f14f4SXin Li 		return die_c_("during FLAC__metadata_chain_write(chain, false, false)", FLAC__metadata_chain_status(chain));
1555*600f14f4SXin Li 	if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
1556*600f14f4SXin Li 		return false;
1557*600f14f4SXin Li 	if(!test_file_(is_ogg, decoder_metadata_callback_compare_))
1558*600f14f4SXin Li 		return false;
1559*600f14f4SXin Li 
1560*600f14f4SXin Li 	printf("SV[A]\tgrow APPLICATION, don't use padding\n");
1561*600f14f4SXin Li 	if(0 == (app = FLAC__metadata_object_clone(our_metadata_.blocks[our_current_position])))
1562*600f14f4SXin Li 		return die_("copying object");
1563*600f14f4SXin Li 	if(!FLAC__metadata_object_application_set_data(app, data, 28, true))
1564*600f14f4SXin Li 		return die_("setting APPLICATION data");
1565*600f14f4SXin Li 	if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1566*600f14f4SXin Li 		return die_("copying object");
1567*600f14f4SXin Li 	if(!FLAC__metadata_iterator_set_block(iterator, app))
1568*600f14f4SXin Li 		return die_c_("FLAC__metadata_iterator_set_block(iterator, app)", FLAC__metadata_chain_status(chain));
1569*600f14f4SXin Li 
1570*600f14f4SXin Li 	if(!write_chain_(chain, /*use_padding=*/false, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg)))
1571*600f14f4SXin Li 		return die_c_("during FLAC__metadata_chain_write(chain, false, false)", FLAC__metadata_chain_status(chain));
1572*600f14f4SXin Li 	if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
1573*600f14f4SXin Li 		return false;
1574*600f14f4SXin Li 	if(!test_file_(is_ogg, decoder_metadata_callback_compare_))
1575*600f14f4SXin Li 		return false;
1576*600f14f4SXin Li 
1577*600f14f4SXin Li 	printf("SV[A]\tgrow APPLICATION, use padding, but last block is not padding\n");
1578*600f14f4SXin Li 	if(0 == (app = FLAC__metadata_object_clone(our_metadata_.blocks[our_current_position])))
1579*600f14f4SXin Li 		return die_("copying object");
1580*600f14f4SXin Li 	if(!FLAC__metadata_object_application_set_data(app, data, 36, true))
1581*600f14f4SXin Li 		return die_("setting APPLICATION data");
1582*600f14f4SXin Li 	if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1583*600f14f4SXin Li 		return die_("copying object");
1584*600f14f4SXin Li 	if(!FLAC__metadata_iterator_set_block(iterator, app))
1585*600f14f4SXin Li 		return die_c_("FLAC__metadata_iterator_set_block(iterator, app)", FLAC__metadata_chain_status(chain));
1586*600f14f4SXin Li 
1587*600f14f4SXin Li 	if(!write_chain_(chain, /*use_padding=*/false, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg)))
1588*600f14f4SXin Li 		return die_c_("during FLAC__metadata_chain_write(chain, false, false)", FLAC__metadata_chain_status(chain));
1589*600f14f4SXin Li 	if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
1590*600f14f4SXin Li 		return false;
1591*600f14f4SXin Li 	if(!test_file_(is_ogg, decoder_metadata_callback_compare_))
1592*600f14f4SXin Li 		return false;
1593*600f14f4SXin Li 
1594*600f14f4SXin Li 	printf("SV[A]\tshrink APPLICATION, use padding, last block is not padding, but delta is too small for new PADDING block\n");
1595*600f14f4SXin Li 	if(0 == (app = FLAC__metadata_object_clone(our_metadata_.blocks[our_current_position])))
1596*600f14f4SXin Li 		return die_("copying object");
1597*600f14f4SXin Li 	if(!FLAC__metadata_object_application_set_data(app, data, 33, true))
1598*600f14f4SXin Li 		return die_("setting APPLICATION data");
1599*600f14f4SXin Li 	if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1600*600f14f4SXin Li 		return die_("copying object");
1601*600f14f4SXin Li 	if(!FLAC__metadata_iterator_set_block(iterator, app))
1602*600f14f4SXin Li 		return die_c_("FLAC__metadata_iterator_set_block(iterator, app)", FLAC__metadata_chain_status(chain));
1603*600f14f4SXin Li 
1604*600f14f4SXin Li 	if(!write_chain_(chain, /*use_padding=*/true, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg)))
1605*600f14f4SXin Li 		return die_c_("during FLAC__metadata_chain_write(chain, true, false)", FLAC__metadata_chain_status(chain));
1606*600f14f4SXin Li 	if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
1607*600f14f4SXin Li 		return false;
1608*600f14f4SXin Li 	if(!test_file_(is_ogg, decoder_metadata_callback_compare_))
1609*600f14f4SXin Li 		return false;
1610*600f14f4SXin Li 
1611*600f14f4SXin Li 	printf("SV[A]\tshrink APPLICATION, use padding, last block is not padding, delta is enough for new PADDING block\n");
1612*600f14f4SXin Li 	if(0 == (padding = FLAC__metadata_object_new(FLAC__METADATA_TYPE_PADDING)))
1613*600f14f4SXin Li 		return die_("creating PADDING block");
1614*600f14f4SXin Li 	if(0 == (app = FLAC__metadata_object_clone(our_metadata_.blocks[our_current_position])))
1615*600f14f4SXin Li 		return die_("copying object");
1616*600f14f4SXin Li 	if(!FLAC__metadata_object_application_set_data(app, data, 29, true))
1617*600f14f4SXin Li 		return die_("setting APPLICATION data");
1618*600f14f4SXin Li 	if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1619*600f14f4SXin Li 		return die_("copying object");
1620*600f14f4SXin Li 	padding->length = 0;
1621*600f14f4SXin Li 	if(!insert_to_our_metadata_(padding, our_current_position+1, /*copy=*/false))
1622*600f14f4SXin Li 		return die_("internal error");
1623*600f14f4SXin Li 	if(!FLAC__metadata_iterator_set_block(iterator, app))
1624*600f14f4SXin Li 		return die_c_("FLAC__metadata_iterator_set_block(iterator, app)", FLAC__metadata_chain_status(chain));
1625*600f14f4SXin Li 
1626*600f14f4SXin Li 	if(!write_chain_(chain, /*use_padding=*/true, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg)))
1627*600f14f4SXin Li 		return die_c_("during FLAC__metadata_chain_write(chain, true, false)", FLAC__metadata_chain_status(chain));
1628*600f14f4SXin Li 	if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
1629*600f14f4SXin Li 		return false;
1630*600f14f4SXin Li 	if(!test_file_(is_ogg, decoder_metadata_callback_compare_))
1631*600f14f4SXin Li 		return false;
1632*600f14f4SXin Li 
1633*600f14f4SXin Li 	printf("SV[A]P\tshrink APPLICATION, use padding, last block is padding\n");
1634*600f14f4SXin Li 	if(0 == (app = FLAC__metadata_object_clone(our_metadata_.blocks[our_current_position])))
1635*600f14f4SXin Li 		return die_("copying object");
1636*600f14f4SXin Li 	if(!FLAC__metadata_object_application_set_data(app, data, 16, true))
1637*600f14f4SXin Li 		return die_("setting APPLICATION data");
1638*600f14f4SXin Li 	if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1639*600f14f4SXin Li 		return die_("copying object");
1640*600f14f4SXin Li 	our_metadata_.blocks[our_current_position+1]->length = 13;
1641*600f14f4SXin Li 	if(!FLAC__metadata_iterator_set_block(iterator, app))
1642*600f14f4SXin Li 		return die_c_("FLAC__metadata_iterator_set_block(iterator, app)", FLAC__metadata_chain_status(chain));
1643*600f14f4SXin Li 
1644*600f14f4SXin Li 	if(!write_chain_(chain, /*use_padding=*/true, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg)))
1645*600f14f4SXin Li 		return die_c_("during FLAC__metadata_chain_write(chain, true, false)", FLAC__metadata_chain_status(chain));
1646*600f14f4SXin Li 	if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
1647*600f14f4SXin Li 		return false;
1648*600f14f4SXin Li 	if(!test_file_(is_ogg, decoder_metadata_callback_compare_))
1649*600f14f4SXin Li 		return false;
1650*600f14f4SXin Li 
1651*600f14f4SXin Li 	printf("SV[A]P\tgrow APPLICATION, use padding, last block is padding, but delta is too small\n");
1652*600f14f4SXin Li 	if(0 == (app = FLAC__metadata_object_clone(our_metadata_.blocks[our_current_position])))
1653*600f14f4SXin Li 		return die_("copying object");
1654*600f14f4SXin Li 	if(!FLAC__metadata_object_application_set_data(app, data, 50, true))
1655*600f14f4SXin Li 		return die_("setting APPLICATION data");
1656*600f14f4SXin Li 	if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1657*600f14f4SXin Li 		return die_("copying object");
1658*600f14f4SXin Li 	if(!FLAC__metadata_iterator_set_block(iterator, app))
1659*600f14f4SXin Li 		return die_c_("FLAC__metadata_iterator_set_block(iterator, app)", FLAC__metadata_chain_status(chain));
1660*600f14f4SXin Li 
1661*600f14f4SXin Li 	if(!write_chain_(chain, /*use_padding=*/true, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg)))
1662*600f14f4SXin Li 		return die_c_("during FLAC__metadata_chain_write(chain, true, false)", FLAC__metadata_chain_status(chain));
1663*600f14f4SXin Li 	if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
1664*600f14f4SXin Li 		return false;
1665*600f14f4SXin Li 	if(!test_file_(is_ogg, decoder_metadata_callback_compare_))
1666*600f14f4SXin Li 		return false;
1667*600f14f4SXin Li 
1668*600f14f4SXin Li 	printf("SV[A]P\tgrow APPLICATION, use padding, last block is padding of exceeding size\n");
1669*600f14f4SXin Li 	if(0 == (app = FLAC__metadata_object_clone(our_metadata_.blocks[our_current_position])))
1670*600f14f4SXin Li 		return die_("copying object");
1671*600f14f4SXin Li 	if(!FLAC__metadata_object_application_set_data(app, data, 56, true))
1672*600f14f4SXin Li 		return die_("setting APPLICATION data");
1673*600f14f4SXin Li 	if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1674*600f14f4SXin Li 		return die_("copying object");
1675*600f14f4SXin Li 	our_metadata_.blocks[our_current_position+1]->length -= (56 - 50);
1676*600f14f4SXin Li 	if(!FLAC__metadata_iterator_set_block(iterator, app))
1677*600f14f4SXin Li 		return die_c_("FLAC__metadata_iterator_set_block(iterator, app)", FLAC__metadata_chain_status(chain));
1678*600f14f4SXin Li 
1679*600f14f4SXin Li 	if(!write_chain_(chain, /*use_padding=*/true, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg)))
1680*600f14f4SXin Li 		return die_c_("during FLAC__metadata_chain_write(chain, true, false)", FLAC__metadata_chain_status(chain));
1681*600f14f4SXin Li 	if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
1682*600f14f4SXin Li 		return false;
1683*600f14f4SXin Li 	if(!test_file_(is_ogg, decoder_metadata_callback_compare_))
1684*600f14f4SXin Li 		return false;
1685*600f14f4SXin Li 
1686*600f14f4SXin Li 	printf("SV[A]P\tgrow APPLICATION, use padding, last block is padding of exact size\n");
1687*600f14f4SXin Li 	if(0 == (app = FLAC__metadata_object_clone(our_metadata_.blocks[our_current_position])))
1688*600f14f4SXin Li 		return die_("copying object");
1689*600f14f4SXin Li 	if(!FLAC__metadata_object_application_set_data(app, data, 67, true))
1690*600f14f4SXin Li 		return die_("setting APPLICATION data");
1691*600f14f4SXin Li 	if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
1692*600f14f4SXin Li 		return die_("copying object");
1693*600f14f4SXin Li 	delete_from_our_metadata_(our_current_position+1);
1694*600f14f4SXin Li 	if(!FLAC__metadata_iterator_set_block(iterator, app))
1695*600f14f4SXin Li 		return die_c_("FLAC__metadata_iterator_set_block(iterator, app)", FLAC__metadata_chain_status(chain));
1696*600f14f4SXin Li 
1697*600f14f4SXin Li 	if(!write_chain_(chain, /*use_padding=*/true, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg)))
1698*600f14f4SXin Li 		return die_c_("during FLAC__metadata_chain_write(chain, true, false)", FLAC__metadata_chain_status(chain));
1699*600f14f4SXin Li 	if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
1700*600f14f4SXin Li 		return false;
1701*600f14f4SXin Li 	if(!test_file_(is_ogg, decoder_metadata_callback_compare_))
1702*600f14f4SXin Li 		return false;
1703*600f14f4SXin Li 
1704*600f14f4SXin Li 	printf("SV[A]\tprev\n");
1705*600f14f4SXin Li 	if(!FLAC__metadata_iterator_prev(iterator))
1706*600f14f4SXin Li 		return die_("iterator ended early\n");
1707*600f14f4SXin Li 	our_current_position--;
1708*600f14f4SXin Li 
1709*600f14f4SXin Li 	printf("S[V]A\tprev\n");
1710*600f14f4SXin Li 	if(!FLAC__metadata_iterator_prev(iterator))
1711*600f14f4SXin Li 		return die_("iterator ended early\n");
1712*600f14f4SXin Li 	our_current_position--;
1713*600f14f4SXin Li 
1714*600f14f4SXin Li 	printf("[S]VA\tinsert PADDING before STREAMINFO (should fail)\n");
1715*600f14f4SXin Li 	if(0 == (padding = FLAC__metadata_object_new(FLAC__METADATA_TYPE_PADDING)))
1716*600f14f4SXin Li 		return die_("creating PADDING block");
1717*600f14f4SXin Li 	padding->length = 30;
1718*600f14f4SXin Li 	if(!FLAC__metadata_iterator_insert_block_before(iterator, padding))
1719*600f14f4SXin Li 		printf("\tFLAC__metadata_iterator_insert_block_before() returned false like it should\n");
1720*600f14f4SXin Li 	else
1721*600f14f4SXin Li 		return die_("FLAC__metadata_iterator_insert_block_before() should have returned false");
1722*600f14f4SXin Li 
1723*600f14f4SXin Li 	printf("[S]VP\tnext\n");
1724*600f14f4SXin Li 	if(!FLAC__metadata_iterator_next(iterator))
1725*600f14f4SXin Li 		return die_("iterator ended early\n");
1726*600f14f4SXin Li 	our_current_position++;
1727*600f14f4SXin Li 
1728*600f14f4SXin Li 	printf("S[V]A\tinsert PADDING after\n");
1729*600f14f4SXin Li 	if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
1730*600f14f4SXin Li 		return die_("copying metadata");
1731*600f14f4SXin Li 	if(!FLAC__metadata_iterator_insert_block_after(iterator, padding))
1732*600f14f4SXin Li 		return die_("FLAC__metadata_iterator_insert_block_after(iterator, padding)");
1733*600f14f4SXin Li 
1734*600f14f4SXin Li 	if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
1735*600f14f4SXin Li 		return false;
1736*600f14f4SXin Li 
1737*600f14f4SXin Li 	printf("SV[P]A\tinsert PADDING before\n");
1738*600f14f4SXin Li 	if(0 == (padding = FLAC__metadata_object_clone(our_metadata_.blocks[our_current_position])))
1739*600f14f4SXin Li 		return die_("creating PADDING block");
1740*600f14f4SXin Li 	padding->length = 17;
1741*600f14f4SXin Li 	if(!insert_to_our_metadata_(padding, our_current_position, /*copy=*/true))
1742*600f14f4SXin Li 		return die_("copying metadata");
1743*600f14f4SXin Li 	if(!FLAC__metadata_iterator_insert_block_before(iterator, padding))
1744*600f14f4SXin Li 		return die_("FLAC__metadata_iterator_insert_block_before(iterator, padding)");
1745*600f14f4SXin Li 
1746*600f14f4SXin Li 	if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
1747*600f14f4SXin Li 		return false;
1748*600f14f4SXin Li 
1749*600f14f4SXin Li 	printf("SV[P]PA\tinsert PADDING before\n");
1750*600f14f4SXin Li 	if(0 == (padding = FLAC__metadata_object_clone(our_metadata_.blocks[our_current_position])))
1751*600f14f4SXin Li 		return die_("creating PADDING block");
1752*600f14f4SXin Li 	padding->length = 0;
1753*600f14f4SXin Li 	if(!insert_to_our_metadata_(padding, our_current_position, /*copy=*/true))
1754*600f14f4SXin Li 		return die_("copying metadata");
1755*600f14f4SXin Li 	if(!FLAC__metadata_iterator_insert_block_before(iterator, padding))
1756*600f14f4SXin Li 		return die_("FLAC__metadata_iterator_insert_block_before(iterator, padding)");
1757*600f14f4SXin Li 
1758*600f14f4SXin Li 	if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
1759*600f14f4SXin Li 		return false;
1760*600f14f4SXin Li 
1761*600f14f4SXin Li 	printf("SV[P]PPA\tnext\n");
1762*600f14f4SXin Li 	if(!FLAC__metadata_iterator_next(iterator))
1763*600f14f4SXin Li 		return die_("iterator ended early\n");
1764*600f14f4SXin Li 	our_current_position++;
1765*600f14f4SXin Li 
1766*600f14f4SXin Li 	printf("SVP[P]PA\tnext\n");
1767*600f14f4SXin Li 	if(!FLAC__metadata_iterator_next(iterator))
1768*600f14f4SXin Li 		return die_("iterator ended early\n");
1769*600f14f4SXin Li 	our_current_position++;
1770*600f14f4SXin Li 
1771*600f14f4SXin Li 	printf("SVPP[P]A\tnext\n");
1772*600f14f4SXin Li 	if(!FLAC__metadata_iterator_next(iterator))
1773*600f14f4SXin Li 		return die_("iterator ended early\n");
1774*600f14f4SXin Li 	our_current_position++;
1775*600f14f4SXin Li 
1776*600f14f4SXin Li 	printf("SVPPP[A]\tinsert PADDING after\n");
1777*600f14f4SXin Li 	if(0 == (padding = FLAC__metadata_object_clone(our_metadata_.blocks[2])))
1778*600f14f4SXin Li 		return die_("creating PADDING block");
1779*600f14f4SXin Li 	padding->length = 57;
1780*600f14f4SXin Li 	if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
1781*600f14f4SXin Li 		return die_("copying metadata");
1782*600f14f4SXin Li 	if(!FLAC__metadata_iterator_insert_block_after(iterator, padding))
1783*600f14f4SXin Li 		return die_("FLAC__metadata_iterator_insert_block_after(iterator, padding)");
1784*600f14f4SXin Li 
1785*600f14f4SXin Li 	if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
1786*600f14f4SXin Li 		return false;
1787*600f14f4SXin Li 
1788*600f14f4SXin Li 	printf("SVPPPA[P]\tinsert PADDING before\n");
1789*600f14f4SXin Li 	if(0 == (padding = FLAC__metadata_object_clone(our_metadata_.blocks[2])))
1790*600f14f4SXin Li 		return die_("creating PADDING block");
1791*600f14f4SXin Li 	padding->length = 99;
1792*600f14f4SXin Li 	if(!insert_to_our_metadata_(padding, our_current_position, /*copy=*/true))
1793*600f14f4SXin Li 		return die_("copying metadata");
1794*600f14f4SXin Li 	if(!FLAC__metadata_iterator_insert_block_before(iterator, padding))
1795*600f14f4SXin Li 		return die_("FLAC__metadata_iterator_insert_block_before(iterator, padding)");
1796*600f14f4SXin Li 
1797*600f14f4SXin Li 	if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
1798*600f14f4SXin Li 		return false;
1799*600f14f4SXin Li 
1800*600f14f4SXin Li 	printf("delete iterator\n");
1801*600f14f4SXin Li 	FLAC__metadata_iterator_delete(iterator);
1802*600f14f4SXin Li 	our_current_position = 0;
1803*600f14f4SXin Li 
1804*600f14f4SXin Li 	printf("SVPPPAPP\tmerge padding\n");
1805*600f14f4SXin Li 	FLAC__metadata_chain_merge_padding(chain);
1806*600f14f4SXin Li 	our_metadata_.blocks[2]->length += (FLAC__STREAM_METADATA_HEADER_LENGTH + our_metadata_.blocks[3]->length);
1807*600f14f4SXin Li 	our_metadata_.blocks[2]->length += (FLAC__STREAM_METADATA_HEADER_LENGTH + our_metadata_.blocks[4]->length);
1808*600f14f4SXin Li 	our_metadata_.blocks[6]->length += (FLAC__STREAM_METADATA_HEADER_LENGTH + our_metadata_.blocks[7]->length);
1809*600f14f4SXin Li 	delete_from_our_metadata_(7);
1810*600f14f4SXin Li 	delete_from_our_metadata_(4);
1811*600f14f4SXin Li 	delete_from_our_metadata_(3);
1812*600f14f4SXin Li 
1813*600f14f4SXin Li 	if(!write_chain_(chain, /*use_padding=*/true, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg)))
1814*600f14f4SXin Li 		return die_c_("during FLAC__metadata_chain_write(chain, true, false)", FLAC__metadata_chain_status(chain));
1815*600f14f4SXin Li 	if(!compare_chain_(chain, 0, 0))
1816*600f14f4SXin Li 		return false;
1817*600f14f4SXin Li 	if(!test_file_(is_ogg, decoder_metadata_callback_compare_))
1818*600f14f4SXin Li 		return false;
1819*600f14f4SXin Li 
1820*600f14f4SXin Li 	printf("SVPAP\tsort padding\n");
1821*600f14f4SXin Li 	FLAC__metadata_chain_sort_padding(chain);
1822*600f14f4SXin Li 	our_metadata_.blocks[4]->length += (FLAC__STREAM_METADATA_HEADER_LENGTH + our_metadata_.blocks[2]->length);
1823*600f14f4SXin Li 	delete_from_our_metadata_(2);
1824*600f14f4SXin Li 
1825*600f14f4SXin Li 	if(!write_chain_(chain, /*use_padding=*/true, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg)))
1826*600f14f4SXin Li 		return die_c_("during FLAC__metadata_chain_write(chain, true, false)", FLAC__metadata_chain_status(chain));
1827*600f14f4SXin Li 	if(!compare_chain_(chain, 0, 0))
1828*600f14f4SXin Li 		return false;
1829*600f14f4SXin Li 	if(!test_file_(is_ogg, decoder_metadata_callback_compare_))
1830*600f14f4SXin Li 		return false;
1831*600f14f4SXin Li 
1832*600f14f4SXin Li 	printf("create iterator\n");
1833*600f14f4SXin Li 	if(0 == (iterator = FLAC__metadata_iterator_new()))
1834*600f14f4SXin Li 		return die_("allocating memory for iterator");
1835*600f14f4SXin Li 
1836*600f14f4SXin Li 	our_current_position = 0;
1837*600f14f4SXin Li 
1838*600f14f4SXin Li 	FLAC__metadata_iterator_init(iterator, chain);
1839*600f14f4SXin Li 
1840*600f14f4SXin Li 	printf("[S]VAP\tnext\n");
1841*600f14f4SXin Li 	if(!FLAC__metadata_iterator_next(iterator))
1842*600f14f4SXin Li 		return die_("iterator ended early\n");
1843*600f14f4SXin Li 	our_current_position++;
1844*600f14f4SXin Li 
1845*600f14f4SXin Li 	printf("S[V]AP\tnext\n");
1846*600f14f4SXin Li 	if(!FLAC__metadata_iterator_next(iterator))
1847*600f14f4SXin Li 		return die_("iterator ended early\n");
1848*600f14f4SXin Li 	our_current_position++;
1849*600f14f4SXin Li 
1850*600f14f4SXin Li 	printf("SV[A]P\tdelete middle block, replace with padding\n");
1851*600f14f4SXin Li 	if(0 == (padding = FLAC__metadata_object_new(FLAC__METADATA_TYPE_PADDING)))
1852*600f14f4SXin Li 		return die_("creating PADDING block");
1853*600f14f4SXin Li 	padding->length = 71;
1854*600f14f4SXin Li 	if(!replace_in_our_metadata_(padding, our_current_position--, /*copy=*/false))
1855*600f14f4SXin Li 		return die_("copying object");
1856*600f14f4SXin Li 	if(!FLAC__metadata_iterator_delete_block(iterator, /*replace_with_padding=*/true))
1857*600f14f4SXin Li 		return die_c_("FLAC__metadata_iterator_delete_block(iterator, true)", FLAC__metadata_chain_status(chain));
1858*600f14f4SXin Li 
1859*600f14f4SXin Li 	if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
1860*600f14f4SXin Li 		return false;
1861*600f14f4SXin Li 
1862*600f14f4SXin Li 	printf("S[V]PP\tnext\n");
1863*600f14f4SXin Li 	if(!FLAC__metadata_iterator_next(iterator))
1864*600f14f4SXin Li 		return die_("iterator ended early\n");
1865*600f14f4SXin Li 	our_current_position++;
1866*600f14f4SXin Li 
1867*600f14f4SXin Li 	printf("SV[P]P\tdelete middle block, don't replace with padding\n");
1868*600f14f4SXin Li 	delete_from_our_metadata_(our_current_position--);
1869*600f14f4SXin Li 	if(!FLAC__metadata_iterator_delete_block(iterator, /*replace_with_padding=*/false))
1870*600f14f4SXin Li 		return die_c_("FLAC__metadata_iterator_delete_block(iterator, false)", FLAC__metadata_chain_status(chain));
1871*600f14f4SXin Li 
1872*600f14f4SXin Li 	if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
1873*600f14f4SXin Li 		return false;
1874*600f14f4SXin Li 
1875*600f14f4SXin Li 	printf("S[V]P\tnext\n");
1876*600f14f4SXin Li 	if(!FLAC__metadata_iterator_next(iterator))
1877*600f14f4SXin Li 		return die_("iterator ended early\n");
1878*600f14f4SXin Li 	our_current_position++;
1879*600f14f4SXin Li 
1880*600f14f4SXin Li 	printf("SV[P]\tdelete last block, replace with padding\n");
1881*600f14f4SXin Li 	if(0 == (padding = FLAC__metadata_object_new(FLAC__METADATA_TYPE_PADDING)))
1882*600f14f4SXin Li 		return die_("creating PADDING block");
1883*600f14f4SXin Li 	padding->length = 219;
1884*600f14f4SXin Li 	if(!replace_in_our_metadata_(padding, our_current_position--, /*copy=*/false))
1885*600f14f4SXin Li 		return die_("copying object");
1886*600f14f4SXin Li 	if(!FLAC__metadata_iterator_delete_block(iterator, /*replace_with_padding=*/true))
1887*600f14f4SXin Li 		return die_c_("FLAC__metadata_iterator_delete_block(iterator, true)", FLAC__metadata_chain_status(chain));
1888*600f14f4SXin Li 
1889*600f14f4SXin Li 	if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
1890*600f14f4SXin Li 		return false;
1891*600f14f4SXin Li 
1892*600f14f4SXin Li 	printf("S[V]P\tnext\n");
1893*600f14f4SXin Li 	if(!FLAC__metadata_iterator_next(iterator))
1894*600f14f4SXin Li 		return die_("iterator ended early\n");
1895*600f14f4SXin Li 	our_current_position++;
1896*600f14f4SXin Li 
1897*600f14f4SXin Li 	printf("SV[P]\tdelete last block, don't replace with padding\n");
1898*600f14f4SXin Li 	delete_from_our_metadata_(our_current_position--);
1899*600f14f4SXin Li 	if(!FLAC__metadata_iterator_delete_block(iterator, /*replace_with_padding=*/false))
1900*600f14f4SXin Li 		return die_c_("FLAC__metadata_iterator_delete_block(iterator, false)", FLAC__metadata_chain_status(chain));
1901*600f14f4SXin Li 
1902*600f14f4SXin Li 	if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
1903*600f14f4SXin Li 		return false;
1904*600f14f4SXin Li 
1905*600f14f4SXin Li 	printf("S[V]\tprev\n");
1906*600f14f4SXin Li 	if(!FLAC__metadata_iterator_prev(iterator))
1907*600f14f4SXin Li 		return die_("iterator ended early\n");
1908*600f14f4SXin Li 	our_current_position--;
1909*600f14f4SXin Li 
1910*600f14f4SXin Li 	printf("[S]V\tdelete STREAMINFO block, should fail\n");
1911*600f14f4SXin Li 	if(FLAC__metadata_iterator_delete_block(iterator, /*replace_with_padding=*/false))
1912*600f14f4SXin Li 		return die_("FLAC__metadata_iterator_delete_block() on STREAMINFO should have failed but didn't");
1913*600f14f4SXin Li 
1914*600f14f4SXin Li 	if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
1915*600f14f4SXin Li 		return false;
1916*600f14f4SXin Li 
1917*600f14f4SXin Li 	printf("delete iterator\n");
1918*600f14f4SXin Li 	FLAC__metadata_iterator_delete(iterator);
1919*600f14f4SXin Li 	our_current_position = 0;
1920*600f14f4SXin Li 
1921*600f14f4SXin Li 	printf("SV\tmerge padding\n");
1922*600f14f4SXin Li 	FLAC__metadata_chain_merge_padding(chain);
1923*600f14f4SXin Li 
1924*600f14f4SXin Li 	if(!write_chain_(chain, /*use_padding=*/false, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg)))
1925*600f14f4SXin Li 		return die_c_("during FLAC__metadata_chain_write(chain, false, false)", FLAC__metadata_chain_status(chain));
1926*600f14f4SXin Li 	if(!compare_chain_(chain, 0, 0))
1927*600f14f4SXin Li 		return false;
1928*600f14f4SXin Li 	if(!test_file_(is_ogg, decoder_metadata_callback_compare_))
1929*600f14f4SXin Li 		return false;
1930*600f14f4SXin Li 
1931*600f14f4SXin Li 	printf("SV\tsort padding\n");
1932*600f14f4SXin Li 	FLAC__metadata_chain_sort_padding(chain);
1933*600f14f4SXin Li 
1934*600f14f4SXin Li 	if(!write_chain_(chain, /*use_padding=*/false, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg)))
1935*600f14f4SXin Li 		return die_c_("during FLAC__metadata_chain_write(chain, false, false)", FLAC__metadata_chain_status(chain));
1936*600f14f4SXin Li 	if(!compare_chain_(chain, 0, 0))
1937*600f14f4SXin Li 		return false;
1938*600f14f4SXin Li 	if(!test_file_(is_ogg, decoder_metadata_callback_compare_))
1939*600f14f4SXin Li 		return false;
1940*600f14f4SXin Li 
1941*600f14f4SXin Li end:
1942*600f14f4SXin Li 	printf("delete chain\n");
1943*600f14f4SXin Li 
1944*600f14f4SXin Li 	FLAC__metadata_chain_delete(chain);
1945*600f14f4SXin Li 
1946*600f14f4SXin Li 	if(!remove_file_(flacfilename(is_ogg)))
1947*600f14f4SXin Li 		return false;
1948*600f14f4SXin Li 
1949*600f14f4SXin Li 	return true;
1950*600f14f4SXin Li }
1951*600f14f4SXin Li 
test_level_2_misc_(FLAC__bool is_ogg)1952*600f14f4SXin Li static FLAC__bool test_level_2_misc_(FLAC__bool is_ogg)
1953*600f14f4SXin Li {
1954*600f14f4SXin Li 	FLAC__Metadata_Iterator *iterator;
1955*600f14f4SXin Li 	FLAC__Metadata_Chain *chain;
1956*600f14f4SXin Li 	FLAC__IOCallbacks callbacks;
1957*600f14f4SXin Li 
1958*600f14f4SXin Li 	memset(&callbacks, 0, sizeof(callbacks));
1959*600f14f4SXin Li 	callbacks.read = (FLAC__IOCallback_Read)fread;
1960*600f14f4SXin Li #ifdef FLAC__VALGRIND_TESTING
1961*600f14f4SXin Li 	callbacks.write = chain_write_cb_;
1962*600f14f4SXin Li #else
1963*600f14f4SXin Li 	callbacks.write = (FLAC__IOCallback_Write)fwrite;
1964*600f14f4SXin Li #endif
1965*600f14f4SXin Li 	callbacks.seek = chain_seek_cb_;
1966*600f14f4SXin Li 	callbacks.tell = chain_tell_cb_;
1967*600f14f4SXin Li 	callbacks.eof = chain_eof_cb_;
1968*600f14f4SXin Li 
1969*600f14f4SXin Li 	printf("\n\n++++++ testing level 2 interface (mismatched read/write protections)\n");
1970*600f14f4SXin Li 
1971*600f14f4SXin Li 	printf("generate file\n");
1972*600f14f4SXin Li 
1973*600f14f4SXin Li 	if(!generate_file_(/*include_extras=*/false, is_ogg))
1974*600f14f4SXin Li 		return false;
1975*600f14f4SXin Li 
1976*600f14f4SXin Li 	printf("create chain\n");
1977*600f14f4SXin Li 
1978*600f14f4SXin Li 	if(0 == (chain = FLAC__metadata_chain_new()))
1979*600f14f4SXin Li 		return die_("allocating chain");
1980*600f14f4SXin Li 
1981*600f14f4SXin Li 	printf("read chain (filename-based)\n");
1982*600f14f4SXin Li 
1983*600f14f4SXin Li 	if(!FLAC__metadata_chain_read(chain, flacfilename(is_ogg)))
1984*600f14f4SXin Li 		return die_c_("reading chain", FLAC__metadata_chain_status(chain));
1985*600f14f4SXin Li 
1986*600f14f4SXin Li 	printf("write chain with wrong method FLAC__metadata_chain_write_with_callbacks()\n");
1987*600f14f4SXin Li 	{
1988*600f14f4SXin Li 		if(FLAC__metadata_chain_write_with_callbacks(chain, /*use_padding=*/false, 0, callbacks))
1989*600f14f4SXin Li 			return die_c_("mismatched write should have failed", FLAC__metadata_chain_status(chain));
1990*600f14f4SXin Li 		if(FLAC__metadata_chain_status(chain) != FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH)
1991*600f14f4SXin Li 			return die_c_("expected FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH", FLAC__metadata_chain_status(chain));
1992*600f14f4SXin Li 		printf("  OK: FLAC__metadata_chain_write_with_callbacks() returned false,FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH like it should\n");
1993*600f14f4SXin Li 	}
1994*600f14f4SXin Li 
1995*600f14f4SXin Li 	printf("read chain (filename-based)\n");
1996*600f14f4SXin Li 
1997*600f14f4SXin Li 	if(!FLAC__metadata_chain_read(chain, flacfilename(is_ogg)))
1998*600f14f4SXin Li 		return die_c_("reading chain", FLAC__metadata_chain_status(chain));
1999*600f14f4SXin Li 
2000*600f14f4SXin Li 	printf("write chain with wrong method FLAC__metadata_chain_write_with_callbacks_and_tempfile()\n");
2001*600f14f4SXin Li 	{
2002*600f14f4SXin Li 		if(FLAC__metadata_chain_write_with_callbacks_and_tempfile(chain, /*use_padding=*/false, 0, callbacks, 0, callbacks))
2003*600f14f4SXin Li 			return die_c_("mismatched write should have failed", FLAC__metadata_chain_status(chain));
2004*600f14f4SXin Li 		if(FLAC__metadata_chain_status(chain) != FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH)
2005*600f14f4SXin Li 			return die_c_("expected FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH", FLAC__metadata_chain_status(chain));
2006*600f14f4SXin Li 		printf("  OK: FLAC__metadata_chain_write_with_callbacks_and_tempfile() returned false,FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH like it should\n");
2007*600f14f4SXin Li 	}
2008*600f14f4SXin Li 
2009*600f14f4SXin Li 	printf("read chain (callback-based)\n");
2010*600f14f4SXin Li 	{
2011*600f14f4SXin Li 		FILE *file = flac_fopen(flacfilename(is_ogg), "rb");
2012*600f14f4SXin Li 		if(0 == file)
2013*600f14f4SXin Li 			return die_("opening file");
2014*600f14f4SXin Li 		if(!FLAC__metadata_chain_read_with_callbacks(chain, (FLAC__IOHandle)file, callbacks)) {
2015*600f14f4SXin Li 			fclose(file);
2016*600f14f4SXin Li 			return die_c_("reading chain", FLAC__metadata_chain_status(chain));
2017*600f14f4SXin Li 		}
2018*600f14f4SXin Li 		fclose(file);
2019*600f14f4SXin Li 	}
2020*600f14f4SXin Li 
2021*600f14f4SXin Li 	printf("write chain with wrong method FLAC__metadata_chain_write()\n");
2022*600f14f4SXin Li 	{
2023*600f14f4SXin Li 		if(FLAC__metadata_chain_write(chain, /*use_padding=*/false, /*preserve_file_stats=*/false))
2024*600f14f4SXin Li 			return die_c_("mismatched write should have failed", FLAC__metadata_chain_status(chain));
2025*600f14f4SXin Li 		if(FLAC__metadata_chain_status(chain) != FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH)
2026*600f14f4SXin Li 			return die_c_("expected FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH", FLAC__metadata_chain_status(chain));
2027*600f14f4SXin Li 		printf("  OK: FLAC__metadata_chain_write() returned false,FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH like it should\n");
2028*600f14f4SXin Li 	}
2029*600f14f4SXin Li 
2030*600f14f4SXin Li 	printf("read chain (callback-based)\n");
2031*600f14f4SXin Li 	{
2032*600f14f4SXin Li 		FILE *file = flac_fopen(flacfilename(is_ogg), "rb");
2033*600f14f4SXin Li 		if(0 == file)
2034*600f14f4SXin Li 			return die_("opening file");
2035*600f14f4SXin Li 		if(!FLAC__metadata_chain_read_with_callbacks(chain, (FLAC__IOHandle)file, callbacks)) {
2036*600f14f4SXin Li 			fclose(file);
2037*600f14f4SXin Li 			return die_c_("reading chain", FLAC__metadata_chain_status(chain));
2038*600f14f4SXin Li 		}
2039*600f14f4SXin Li 		fclose(file);
2040*600f14f4SXin Li 	}
2041*600f14f4SXin Li 
2042*600f14f4SXin Li 	printf("testing FLAC__metadata_chain_check_if_tempfile_needed()... ");
2043*600f14f4SXin Li 
2044*600f14f4SXin Li 	if(!FLAC__metadata_chain_check_if_tempfile_needed(chain, /*use_padding=*/false))
2045*600f14f4SXin Li 		printf("OK: FLAC__metadata_chain_check_if_tempfile_needed() returned false like it should\n");
2046*600f14f4SXin Li 	else
2047*600f14f4SXin Li 		return die_("FLAC__metadata_chain_check_if_tempfile_needed() returned true but shouldn't have");
2048*600f14f4SXin Li 
2049*600f14f4SXin Li 	printf("write chain with wrong method FLAC__metadata_chain_write_with_callbacks_and_tempfile()\n");
2050*600f14f4SXin Li 	{
2051*600f14f4SXin Li 		if(FLAC__metadata_chain_write_with_callbacks_and_tempfile(chain, /*use_padding=*/false, 0, callbacks, 0, callbacks))
2052*600f14f4SXin Li 			return die_c_("mismatched write should have failed", FLAC__metadata_chain_status(chain));
2053*600f14f4SXin Li 		if(FLAC__metadata_chain_status(chain) != FLAC__METADATA_CHAIN_STATUS_WRONG_WRITE_CALL)
2054*600f14f4SXin Li 			return die_c_("expected FLAC__METADATA_CHAIN_STATUS_WRONG_WRITE_CALL", FLAC__metadata_chain_status(chain));
2055*600f14f4SXin Li 		printf("  OK: FLAC__metadata_chain_write_with_callbacks_and_tempfile() returned false,FLAC__METADATA_CHAIN_STATUS_WRONG_WRITE_CALL like it should\n");
2056*600f14f4SXin Li 	}
2057*600f14f4SXin Li 
2058*600f14f4SXin Li 	printf("read chain (callback-based)\n");
2059*600f14f4SXin Li 	{
2060*600f14f4SXin Li 		FILE *file = flac_fopen(flacfilename(is_ogg), "rb");
2061*600f14f4SXin Li 		if(0 == file)
2062*600f14f4SXin Li 			return die_("opening file");
2063*600f14f4SXin Li 		if(!FLAC__metadata_chain_read_with_callbacks(chain, (FLAC__IOHandle)file, callbacks)) {
2064*600f14f4SXin Li 			fclose(file);
2065*600f14f4SXin Li 			return die_c_("reading chain", FLAC__metadata_chain_status(chain));
2066*600f14f4SXin Li 		}
2067*600f14f4SXin Li 		fclose(file);
2068*600f14f4SXin Li 	}
2069*600f14f4SXin Li 
2070*600f14f4SXin Li 	printf("create iterator\n");
2071*600f14f4SXin Li 	if(0 == (iterator = FLAC__metadata_iterator_new()))
2072*600f14f4SXin Li 		return die_("allocating memory for iterator");
2073*600f14f4SXin Li 
2074*600f14f4SXin Li 	FLAC__metadata_iterator_init(iterator, chain);
2075*600f14f4SXin Li 
2076*600f14f4SXin Li 	printf("[S]VP\tnext\n");
2077*600f14f4SXin Li 	if(!FLAC__metadata_iterator_next(iterator))
2078*600f14f4SXin Li 		return die_("iterator ended early\n");
2079*600f14f4SXin Li 
2080*600f14f4SXin Li 	printf("S[V]P\tdelete VORBIS_COMMENT, write\n");
2081*600f14f4SXin Li 	if(!FLAC__metadata_iterator_delete_block(iterator, /*replace_with_padding=*/false))
2082*600f14f4SXin Li 		return die_c_("block delete failed\n", FLAC__metadata_chain_status(chain));
2083*600f14f4SXin Li 
2084*600f14f4SXin Li 	printf("testing FLAC__metadata_chain_check_if_tempfile_needed()... ");
2085*600f14f4SXin Li 
2086*600f14f4SXin Li 	if(FLAC__metadata_chain_check_if_tempfile_needed(chain, /*use_padding=*/false))
2087*600f14f4SXin Li 		printf("OK: FLAC__metadata_chain_check_if_tempfile_needed() returned true like it should\n");
2088*600f14f4SXin Li 	else
2089*600f14f4SXin Li 		return die_("FLAC__metadata_chain_check_if_tempfile_needed() returned false but shouldn't have");
2090*600f14f4SXin Li 
2091*600f14f4SXin Li 	printf("write chain with wrong method FLAC__metadata_chain_write_with_callbacks()\n");
2092*600f14f4SXin Li 	{
2093*600f14f4SXin Li 		if(FLAC__metadata_chain_write_with_callbacks(chain, /*use_padding=*/false, 0, callbacks))
2094*600f14f4SXin Li 			return die_c_("mismatched write should have failed", FLAC__metadata_chain_status(chain));
2095*600f14f4SXin Li 		if(FLAC__metadata_chain_status(chain) != FLAC__METADATA_CHAIN_STATUS_WRONG_WRITE_CALL)
2096*600f14f4SXin Li 			return die_c_("expected FLAC__METADATA_CHAIN_STATUS_WRONG_WRITE_CALL", FLAC__metadata_chain_status(chain));
2097*600f14f4SXin Li 		printf("  OK: FLAC__metadata_chain_write_with_callbacks() returned false,FLAC__METADATA_CHAIN_STATUS_WRONG_WRITE_CALL like it should\n");
2098*600f14f4SXin Li 	}
2099*600f14f4SXin Li 
2100*600f14f4SXin Li 	printf("delete iterator\n");
2101*600f14f4SXin Li 
2102*600f14f4SXin Li 	FLAC__metadata_iterator_delete(iterator);
2103*600f14f4SXin Li 
2104*600f14f4SXin Li 	printf("delete chain\n");
2105*600f14f4SXin Li 
2106*600f14f4SXin Li 	FLAC__metadata_chain_delete(chain);
2107*600f14f4SXin Li 
2108*600f14f4SXin Li 	if(!remove_file_(flacfilename(is_ogg)))
2109*600f14f4SXin Li 		return false;
2110*600f14f4SXin Li 
2111*600f14f4SXin Li 	return true;
2112*600f14f4SXin Li }
2113*600f14f4SXin Li 
test_metadata_file_manipulation(void)2114*600f14f4SXin Li FLAC__bool test_metadata_file_manipulation(void)
2115*600f14f4SXin Li {
2116*600f14f4SXin Li 	printf("\n+++ libFLAC unit test: metadata manipulation\n\n");
2117*600f14f4SXin Li 
2118*600f14f4SXin Li 	our_metadata_.num_blocks = 0;
2119*600f14f4SXin Li 
2120*600f14f4SXin Li 	if(!test_level_0_())
2121*600f14f4SXin Li 		return false;
2122*600f14f4SXin Li 
2123*600f14f4SXin Li 	if(!test_level_1_())
2124*600f14f4SXin Li 		return false;
2125*600f14f4SXin Li 
2126*600f14f4SXin Li 	if(!test_level_2_(/*filename_based=*/true, /*is_ogg=*/false)) /* filename-based */
2127*600f14f4SXin Li 		return false;
2128*600f14f4SXin Li 	if(!test_level_2_(/*filename_based=*/false, /*is_ogg=*/false)) /* callback-based */
2129*600f14f4SXin Li 		return false;
2130*600f14f4SXin Li 	if(!test_level_2_misc_(/*is_ogg=*/false))
2131*600f14f4SXin Li 		return false;
2132*600f14f4SXin Li 
2133*600f14f4SXin Li 	if(FLAC_API_SUPPORTS_OGG_FLAC) {
2134*600f14f4SXin Li 		if(!test_level_2_(/*filename_based=*/true, /*is_ogg=*/true)) /* filename-based */
2135*600f14f4SXin Li 			return false;
2136*600f14f4SXin Li 		if(!test_level_2_(/*filename_based=*/false, /*is_ogg=*/true)) /* callback-based */
2137*600f14f4SXin Li 			return false;
2138*600f14f4SXin Li #if 0
2139*600f14f4SXin Li 		/* when ogg flac write is supported, will have to add this: */
2140*600f14f4SXin Li 		if(!test_level_2_misc_(/*is_ogg=*/true))
2141*600f14f4SXin Li 			return false;
2142*600f14f4SXin Li #endif
2143*600f14f4SXin Li 	}
2144*600f14f4SXin Li 
2145*600f14f4SXin Li 	return true;
2146*600f14f4SXin Li }
2147