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