xref: /aosp_15_r20/external/flac/oss-fuzz/metadata.cc (revision 600f14f40d737144c998e2ec7a483122d3776fbc)
1*600f14f4SXin Li /* fuzzer_metadata
2*600f14f4SXin Li  * Copyright (C) 2022-2023  Xiph.Org Foundation
3*600f14f4SXin Li  *
4*600f14f4SXin Li  * Redistribution and use in source and binary forms, with or without
5*600f14f4SXin Li  * modification, are permitted provided that the following conditions
6*600f14f4SXin Li  * are met:
7*600f14f4SXin Li  *
8*600f14f4SXin Li  * - Redistributions of source code must retain the above copyright
9*600f14f4SXin Li  * notice, this list of conditions and the following disclaimer.
10*600f14f4SXin Li  *
11*600f14f4SXin Li  * - Redistributions in binary form must reproduce the above copyright
12*600f14f4SXin Li  * notice, this list of conditions and the following disclaimer in the
13*600f14f4SXin Li  * documentation and/or other materials provided with the distribution.
14*600f14f4SXin Li  *
15*600f14f4SXin Li  * - Neither the name of the Xiph.org Foundation nor the names of its
16*600f14f4SXin Li  * contributors may be used to endorse or promote products derived from
17*600f14f4SXin Li  * this software without specific prior written permission.
18*600f14f4SXin Li  *
19*600f14f4SXin Li  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20*600f14f4SXin Li  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21*600f14f4SXin Li  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22*600f14f4SXin Li  * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
23*600f14f4SXin Li  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
24*600f14f4SXin Li  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
25*600f14f4SXin Li  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
26*600f14f4SXin Li  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
27*600f14f4SXin Li  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
28*600f14f4SXin Li  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
29*600f14f4SXin Li  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30*600f14f4SXin Li  */
31*600f14f4SXin Li 
32*600f14f4SXin Li #include <cstdlib>
33*600f14f4SXin Li #include <cstdio>
34*600f14f4SXin Li #include <cstring> /* for memcpy */
35*600f14f4SXin Li #include <unistd.h>
36*600f14f4SXin Li #include "FLAC++/metadata.h"
37*600f14f4SXin Li #include "common.h"
38*600f14f4SXin Li 
39*600f14f4SXin Li #define CONFIG_LENGTH 2
40*600f14f4SXin Li 
41*600f14f4SXin Li #define min(x,y) (x<y?x:y)
42*600f14f4SXin Li 
43*600f14f4SXin Li static void run_tests_with_level_0_interface(char filename[]);
44*600f14f4SXin Li static void run_tests_with_level_1_interface(char filename[], bool readonly, bool preservestats, const uint8_t *data, size_t size);
45*600f14f4SXin Li static void run_tests_with_level_2_interface(char filename[], bool ogg, bool use_padding, const uint8_t *data, size_t size);
46*600f14f4SXin Li 
LLVMFuzzerTestOneInput(const uint8_t * data,size_t size)47*600f14f4SXin Li extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
48*600f14f4SXin Li {
49*600f14f4SXin Li 	uint8_t command_length;
50*600f14f4SXin Li 	char filename[] = "/tmp/tmpXXXXXX.flac";
51*600f14f4SXin Li 	FLAC__bool init_bools[4];
52*600f14f4SXin Li 
53*600f14f4SXin Li 	/* Use first byte for configuration, leave at least one byte of input */
54*600f14f4SXin Li 	if(size < 1 + CONFIG_LENGTH){
55*600f14f4SXin Li 		return 0;
56*600f14f4SXin Li 	}
57*600f14f4SXin Li 
58*600f14f4SXin Li 	/* First 4 bits for configuration bools, next 4 for length of command section */
59*600f14f4SXin Li 	for(int i = 0; i < 4; i++)
60*600f14f4SXin Li 		init_bools[i] = data[i/8] & (1 << (i % 8));
61*600f14f4SXin Li 
62*600f14f4SXin Li 	command_length = data[0] >> 4;
63*600f14f4SXin Li 
64*600f14f4SXin Li 	if(0)//data[1] < 128) /* Use MSB as on/off */
65*600f14f4SXin Li 		alloc_check_threshold = data[1];
66*600f14f4SXin Li 	else
67*600f14f4SXin Li 		alloc_check_threshold = INT32_MAX;
68*600f14f4SXin Li 	alloc_check_counter = 0;
69*600f14f4SXin Li 
70*600f14f4SXin Li 
71*600f14f4SXin Li 	/* Leave at least one byte as input */
72*600f14f4SXin Li 	if(command_length >= size - 1 - CONFIG_LENGTH)
73*600f14f4SXin Li 		command_length = size - 1 - CONFIG_LENGTH;
74*600f14f4SXin Li 
75*600f14f4SXin Li 	/* Dump input to file */
76*600f14f4SXin Li 	{
77*600f14f4SXin Li 		int file_to_fuzz = mkstemps(filename, 5);
78*600f14f4SXin Li 
79*600f14f4SXin Li 		if (file_to_fuzz < 0)
80*600f14f4SXin Li 			abort();
81*600f14f4SXin Li 		write(file_to_fuzz,data+CONFIG_LENGTH+command_length,size-CONFIG_LENGTH-command_length);
82*600f14f4SXin Li 		close(file_to_fuzz);
83*600f14f4SXin Li 	}
84*600f14f4SXin Li 
85*600f14f4SXin Li 	run_tests_with_level_0_interface(filename);
86*600f14f4SXin Li 	run_tests_with_level_1_interface(filename, init_bools[1], init_bools[2], data+CONFIG_LENGTH, command_length/2);
87*600f14f4SXin Li 
88*600f14f4SXin Li 	/* Dump input to file, to start fresh for level 2 */
89*600f14f4SXin Li 	if(!init_bools[1]){
90*600f14f4SXin Li 		FILE * file_to_fuzz = fopen(filename,"w");
91*600f14f4SXin Li 		fwrite(data+CONFIG_LENGTH+command_length,1,size-CONFIG_LENGTH-command_length,file_to_fuzz);
92*600f14f4SXin Li 		fclose(file_to_fuzz);
93*600f14f4SXin Li 	}
94*600f14f4SXin Li 
95*600f14f4SXin Li 	run_tests_with_level_2_interface(filename, init_bools[0], init_bools[3], data+command_length/2+CONFIG_LENGTH, command_length/2);
96*600f14f4SXin Li 
97*600f14f4SXin Li 	remove(filename);
98*600f14f4SXin Li 
99*600f14f4SXin Li 	return 0;
100*600f14f4SXin Li }
101*600f14f4SXin Li 
run_tests_with_level_0_interface(char filename[])102*600f14f4SXin Li static void run_tests_with_level_0_interface(char filename[]) {
103*600f14f4SXin Li 	FLAC::Metadata::StreamInfo streaminfo;
104*600f14f4SXin Li 	FLAC::Metadata::VorbisComment vorbis_comment;
105*600f14f4SXin Li 	FLAC::Metadata::CueSheet cue_sheet;
106*600f14f4SXin Li 	FLAC::Metadata::Picture picture;
107*600f14f4SXin Li 
108*600f14f4SXin Li 	FLAC::Metadata::get_streaminfo(filename,streaminfo);
109*600f14f4SXin Li 	FLAC::Metadata::get_tags(filename,vorbis_comment);
110*600f14f4SXin Li 	FLAC::Metadata::get_cuesheet(filename,cue_sheet);
111*600f14f4SXin Li 	FLAC::Metadata::get_picture(filename,picture, (FLAC__StreamMetadata_Picture_Type)(1), NULL, NULL, -1, -1, -1, -1);
112*600f14f4SXin Li }
113*600f14f4SXin Li 
run_tests_with_level_1_interface(char filename[],bool readonly,bool preservestats,const uint8_t * data,size_t size)114*600f14f4SXin Li static void run_tests_with_level_1_interface(char filename[], bool readonly, bool preservestats, const uint8_t *data, size_t size) {
115*600f14f4SXin Li 	FLAC::Metadata::SimpleIterator iterator;
116*600f14f4SXin Li 	FLAC::Metadata::Prototype *metadata_block = nullptr;
117*600f14f4SXin Li 	uint8_t id[4] = {0};
118*600f14f4SXin Li 
119*600f14f4SXin Li 	if(!iterator.is_valid())
120*600f14f4SXin Li 		return;
121*600f14f4SXin Li 
122*600f14f4SXin Li 	if(!iterator.init(filename,readonly,preservestats))
123*600f14f4SXin Li 		return;
124*600f14f4SXin Li 
125*600f14f4SXin Li 	for(size_t i = 0; i < size && iterator.status() == FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK; i++) {
126*600f14f4SXin Li 		switch(data[i] & 7) {
127*600f14f4SXin Li 			case 0:
128*600f14f4SXin Li 				iterator.get_block_type();
129*600f14f4SXin Li 				iterator.get_block_offset();
130*600f14f4SXin Li 				iterator.get_block_length();
131*600f14f4SXin Li 				iterator.get_application_id(id);
132*600f14f4SXin Li 				break;
133*600f14f4SXin Li 			case 1:
134*600f14f4SXin Li 				iterator.next();
135*600f14f4SXin Li 				break;
136*600f14f4SXin Li 			case 2:
137*600f14f4SXin Li 				iterator.prev();
138*600f14f4SXin Li 				break;
139*600f14f4SXin Li 			case 3:
140*600f14f4SXin Li 				iterator.delete_block(data[i] & 8);
141*600f14f4SXin Li 				break;
142*600f14f4SXin Li 			case 4:
143*600f14f4SXin Li 				if(metadata_block != 0) {
144*600f14f4SXin Li 					delete metadata_block;
145*600f14f4SXin Li 					metadata_block = nullptr;
146*600f14f4SXin Li 				}
147*600f14f4SXin Li 				metadata_block = iterator.get_block();
148*600f14f4SXin Li 				break;
149*600f14f4SXin Li 			case 5:
150*600f14f4SXin Li 				if(metadata_block != 0)
151*600f14f4SXin Li 					iterator.set_block(metadata_block,data[i] & 8);
152*600f14f4SXin Li 				break;
153*600f14f4SXin Li 			case 6:
154*600f14f4SXin Li 				if(metadata_block != 0)
155*600f14f4SXin Li 					iterator.insert_block_after(metadata_block, data[i] & 8);
156*600f14f4SXin Li 				break;
157*600f14f4SXin Li 			case 7:
158*600f14f4SXin Li 				iterator.status();
159*600f14f4SXin Li 				iterator.is_last();
160*600f14f4SXin Li 				iterator.is_writable();
161*600f14f4SXin Li 				break;
162*600f14f4SXin Li 		}
163*600f14f4SXin Li 	}
164*600f14f4SXin Li 	if(metadata_block != 0) {
165*600f14f4SXin Li 		delete metadata_block;
166*600f14f4SXin Li 		metadata_block = nullptr;
167*600f14f4SXin Li 	}
168*600f14f4SXin Li 
169*600f14f4SXin Li 
170*600f14f4SXin Li }
171*600f14f4SXin Li 
172*600f14f4SXin Li 
run_tests_with_level_2_interface(char filename[],bool ogg,bool use_padding,const uint8_t * data,size_t size)173*600f14f4SXin Li static void run_tests_with_level_2_interface(char filename[], bool ogg, bool use_padding, const uint8_t *data, size_t size) {
174*600f14f4SXin Li 	FLAC::Metadata::Chain chain;
175*600f14f4SXin Li 	FLAC::Metadata::Iterator iterator;
176*600f14f4SXin Li 	FLAC::Metadata::Prototype *metadata_block_get = nullptr;
177*600f14f4SXin Li 	FLAC::Metadata::Prototype *metadata_block_transfer = nullptr;
178*600f14f4SXin Li 	FLAC::Metadata::Prototype *metadata_block_put = nullptr;
179*600f14f4SXin Li 
180*600f14f4SXin Li 	if(!chain.is_valid())
181*600f14f4SXin Li 		return;
182*600f14f4SXin Li 
183*600f14f4SXin Li 	if(!chain.read(filename, ogg))
184*600f14f4SXin Li 		return;
185*600f14f4SXin Li 
186*600f14f4SXin Li 	iterator.init(chain);
187*600f14f4SXin Li 
188*600f14f4SXin Li 	for(size_t i = 0; i < size; i++) {
189*600f14f4SXin Li 		switch(data[i] & 15) {
190*600f14f4SXin Li 			case 0:
191*600f14f4SXin Li 				iterator.get_block_type();
192*600f14f4SXin Li 				break;
193*600f14f4SXin Li 			case 1:
194*600f14f4SXin Li 				iterator.next();
195*600f14f4SXin Li 				break;
196*600f14f4SXin Li 			case 2:
197*600f14f4SXin Li 				iterator.prev();
198*600f14f4SXin Li 				break;
199*600f14f4SXin Li 			case 3:
200*600f14f4SXin Li 				iterator.delete_block(data[i] & 16);
201*600f14f4SXin Li 				break;
202*600f14f4SXin Li 			case 4:
203*600f14f4SXin Li 				metadata_block_get = iterator.get_block();
204*600f14f4SXin Li 				if(metadata_block_get != 0 && metadata_block_get->is_valid()) {
205*600f14f4SXin Li 					if(metadata_block_transfer != 0 && metadata_block_transfer->is_valid()) {
206*600f14f4SXin Li 						if(metadata_block_transfer != metadata_block_get) {
207*600f14f4SXin Li 							delete metadata_block_transfer;
208*600f14f4SXin Li 							metadata_block_transfer = nullptr;
209*600f14f4SXin Li 							metadata_block_transfer = FLAC::Metadata::clone(metadata_block_get);
210*600f14f4SXin Li 						}
211*600f14f4SXin Li 					}
212*600f14f4SXin Li 					else {
213*600f14f4SXin Li 						metadata_block_transfer = FLAC::Metadata::clone(metadata_block_get);
214*600f14f4SXin Li 					}
215*600f14f4SXin Li 				}
216*600f14f4SXin Li 				delete metadata_block_get;
217*600f14f4SXin Li 				break;
218*600f14f4SXin Li 			case 5:
219*600f14f4SXin Li 				if(metadata_block_transfer != 0 && metadata_block_transfer->is_valid()) {
220*600f14f4SXin Li 					metadata_block_put = FLAC::Metadata::clone(metadata_block_transfer);
221*600f14f4SXin Li 					if(metadata_block_put != 0 && metadata_block_put->is_valid()) {
222*600f14f4SXin Li 						if(!iterator.insert_block_before(metadata_block_put))
223*600f14f4SXin Li 							delete metadata_block_put;
224*600f14f4SXin Li 					}
225*600f14f4SXin Li 					else
226*600f14f4SXin Li 						if(metadata_block_put != 0)
227*600f14f4SXin Li 							delete metadata_block_put;
228*600f14f4SXin Li 				}
229*600f14f4SXin Li 				break;
230*600f14f4SXin Li 			case 6:
231*600f14f4SXin Li 				if(metadata_block_transfer != 0 && metadata_block_transfer->is_valid()) {
232*600f14f4SXin Li 					metadata_block_put = FLAC::Metadata::clone(metadata_block_transfer);
233*600f14f4SXin Li 					if(metadata_block_put != 0 && metadata_block_put->is_valid()) {
234*600f14f4SXin Li 						if(!iterator.insert_block_after(metadata_block_put))
235*600f14f4SXin Li 							delete metadata_block_put;
236*600f14f4SXin Li 					}
237*600f14f4SXin Li 					else
238*600f14f4SXin Li 						if(metadata_block_put != 0)
239*600f14f4SXin Li 							delete metadata_block_put;
240*600f14f4SXin Li 				}
241*600f14f4SXin Li 				break;
242*600f14f4SXin Li 			case 7:
243*600f14f4SXin Li 				if(metadata_block_transfer != 0 && metadata_block_transfer->is_valid()) {
244*600f14f4SXin Li 					metadata_block_put = FLAC::Metadata::clone(metadata_block_transfer);
245*600f14f4SXin Li 					if(metadata_block_put != 0 && metadata_block_put->is_valid()) {
246*600f14f4SXin Li 						if(!iterator.set_block(metadata_block_put))
247*600f14f4SXin Li 							delete metadata_block_put;
248*600f14f4SXin Li 					}
249*600f14f4SXin Li 					else
250*600f14f4SXin Li 						if(metadata_block_put != 0)
251*600f14f4SXin Li 							delete metadata_block_put;
252*600f14f4SXin Li 				}
253*600f14f4SXin Li 				break;
254*600f14f4SXin Li 			case 8: /* Examine block */
255*600f14f4SXin Li 				if(metadata_block_transfer != 0 && metadata_block_transfer->is_valid()) {
256*600f14f4SXin Li 					switch(metadata_block_transfer->get_type()) {
257*600f14f4SXin Li 						case FLAC__METADATA_TYPE_VORBIS_COMMENT:
258*600f14f4SXin Li 						{
259*600f14f4SXin Li 							uint32_t num_comments;
260*600f14f4SXin Li 							::FLAC__StreamMetadata_VorbisComment_Entry entry;
261*600f14f4SXin Li 							FLAC::Metadata::VorbisComment::Entry entry_cpp;
262*600f14f4SXin Li 							FLAC::Metadata::VorbisComment * vorbiscomment = dynamic_cast<FLAC::Metadata::VorbisComment *>(metadata_block_transfer);
263*600f14f4SXin Li 							const ::FLAC__StreamMetadata * metadata_c = *metadata_block_transfer;
264*600f14f4SXin Li 							if(vorbiscomment == 0)
265*600f14f4SXin Li 								abort();
266*600f14f4SXin Li 							vorbiscomment->get_vendor_string();
267*600f14f4SXin Li 							num_comments = vorbiscomment->get_num_comments();
268*600f14f4SXin Li 							if(num_comments > 0) {
269*600f14f4SXin Li 								entry = metadata_c->data.vorbis_comment.comments[min(data[i]>>4,num_comments-1)];
270*600f14f4SXin Li 								if(entry.entry == 0)
271*600f14f4SXin Li 									abort();
272*600f14f4SXin Li 								if(vorbiscomment->get_comment(min(data[i]>>4,num_comments-1)).is_valid()) {
273*600f14f4SXin Li 									entry_cpp = vorbiscomment->get_comment(min(data[i]>>4,num_comments-1));
274*600f14f4SXin Li 									if(entry_cpp.is_valid() && entry_cpp.get_field() == 0)
275*600f14f4SXin Li 										abort();
276*600f14f4SXin Li 									vorbiscomment->find_entry_from(0,"TEST");
277*600f14f4SXin Li 								}
278*600f14f4SXin Li 							}
279*600f14f4SXin Li 
280*600f14f4SXin Li 						}
281*600f14f4SXin Li 						break;
282*600f14f4SXin Li 						case FLAC__METADATA_TYPE_CUESHEET:
283*600f14f4SXin Li 						{
284*600f14f4SXin Li 							uint32_t num_tracks, num_indices;
285*600f14f4SXin Li 							FLAC::Metadata::CueSheet * cuesheet = dynamic_cast<FLAC::Metadata::CueSheet *>(metadata_block_transfer);
286*600f14f4SXin Li 							if(cuesheet == 0 || !cuesheet->is_legal())
287*600f14f4SXin Li 								break;
288*600f14f4SXin Li 							cuesheet->is_legal(true); /* check CDDA subset */
289*600f14f4SXin Li 							cuesheet->calculate_cddb_id();
290*600f14f4SXin Li 							cuesheet->get_media_catalog_number();
291*600f14f4SXin Li 							cuesheet->get_lead_in();
292*600f14f4SXin Li 							cuesheet->get_is_cd();
293*600f14f4SXin Li 							num_tracks = cuesheet->get_num_tracks();
294*600f14f4SXin Li 							if(num_tracks > 0) {
295*600f14f4SXin Li 								FLAC::Metadata::CueSheet::Track track = cuesheet->get_track(min(data[i]>>4,num_tracks-1));
296*600f14f4SXin Li 								track.get_offset();
297*600f14f4SXin Li 								track.get_number();
298*600f14f4SXin Li 								track.get_isrc();
299*600f14f4SXin Li 								track.get_pre_emphasis();
300*600f14f4SXin Li 								num_indices = track.get_num_indices();
301*600f14f4SXin Li 								if(num_indices > 0) {
302*600f14f4SXin Li 									FLAC__StreamMetadata_CueSheet_Index index = track.get_index(min(data[i]>>4,num_indices-1));
303*600f14f4SXin Li 									(void)index;
304*600f14f4SXin Li 								}
305*600f14f4SXin Li 							}
306*600f14f4SXin Li 						}
307*600f14f4SXin Li 						break;
308*600f14f4SXin Li 						case FLAC__METADATA_TYPE_PICTURE:
309*600f14f4SXin Li 						{
310*600f14f4SXin Li 							char * violation = nullptr;
311*600f14f4SXin Li 							FLAC::Metadata::Picture * picture = dynamic_cast<FLAC::Metadata::Picture *>(metadata_block_transfer);
312*600f14f4SXin Li 							if(picture == 0 || !picture->is_legal((const char **)&violation))
313*600f14f4SXin Li 								break;
314*600f14f4SXin Li 							picture->get_data();
315*600f14f4SXin Li 						}
316*600f14f4SXin Li 						break;
317*600f14f4SXin Li 						default:
318*600f14f4SXin Li 						break;
319*600f14f4SXin Li 					}
320*600f14f4SXin Li 
321*600f14f4SXin Li 				}
322*600f14f4SXin Li 				break;
323*600f14f4SXin Li 			case 9: /* Replace or add in block */
324*600f14f4SXin Li 				if(metadata_block_transfer != 0 && metadata_block_transfer->is_valid()) {
325*600f14f4SXin Li 					switch(metadata_block_transfer->get_type()) {
326*600f14f4SXin Li 						case FLAC__METADATA_TYPE_SEEKTABLE:
327*600f14f4SXin Li 						{
328*600f14f4SXin Li 							uint32_t num_seekpoints;
329*600f14f4SXin Li 							FLAC__StreamMetadata_SeekPoint seekpoint;
330*600f14f4SXin Li 							FLAC::Metadata::SeekTable * seektable = dynamic_cast<FLAC::Metadata::SeekTable *>(metadata_block_transfer);
331*600f14f4SXin Li 							if(seektable == 0)
332*600f14f4SXin Li 								break;
333*600f14f4SXin Li 							if(seektable->is_valid() && seektable->is_legal()) {
334*600f14f4SXin Li 								num_seekpoints = seektable->get_num_points();
335*600f14f4SXin Li 								if(num_seekpoints > 0) {
336*600f14f4SXin Li 									seekpoint = seektable->get_point(min(data[i]>>5,num_seekpoints-1));
337*600f14f4SXin Li 									seektable->set_point(0,seekpoint);
338*600f14f4SXin Li 									seektable->insert_point(min(data[i]>>5,num_seekpoints-1),seekpoint);
339*600f14f4SXin Li 								}
340*600f14f4SXin Li 								seektable->template_append_placeholders(4);
341*600f14f4SXin Li 								seektable->template_append_point(111111);
342*600f14f4SXin Li 								seektable->template_append_points((FLAC__uint64[]){222222, 333333, 444444}, 3);
343*600f14f4SXin Li 								seektable->template_append_spaced_points(data[i]>>5, 1234567);
344*600f14f4SXin Li 								seektable->template_append_spaced_points_by_samples(data[i]>>5, 2468000);
345*600f14f4SXin Li 								seektable->template_sort(data[i] & 16);
346*600f14f4SXin Li 							}
347*600f14f4SXin Li 						}
348*600f14f4SXin Li 						case FLAC__METADATA_TYPE_VORBIS_COMMENT:
349*600f14f4SXin Li 						{
350*600f14f4SXin Li 							uint32_t num_comments;
351*600f14f4SXin Li 							FLAC::Metadata::VorbisComment::Entry entry;
352*600f14f4SXin Li 							FLAC::Metadata::VorbisComment * vorbiscomment = dynamic_cast<FLAC::Metadata::VorbisComment *>(metadata_block_transfer);
353*600f14f4SXin Li 							if(vorbiscomment == 0)
354*600f14f4SXin Li 								break;
355*600f14f4SXin Li 							num_comments = vorbiscomment->get_num_comments();
356*600f14f4SXin Li 							if(num_comments > 0 && entry.is_valid()) {
357*600f14f4SXin Li 								if(vorbiscomment->get_comment(min(data[i]>>5,num_comments-1)).is_valid()) {
358*600f14f4SXin Li 									entry = vorbiscomment->get_comment(min(data[i]>>5,num_comments-1));
359*600f14f4SXin Li 									if(entry.is_valid()) {
360*600f14f4SXin Li 										vorbiscomment->replace_comment(entry,data[i] & 16);
361*600f14f4SXin Li 										vorbiscomment->set_comment(0,entry);
362*600f14f4SXin Li 										vorbiscomment->append_comment(entry);
363*600f14f4SXin Li 										vorbiscomment->insert_comment(0,entry);
364*600f14f4SXin Li 									}
365*600f14f4SXin Li 								}
366*600f14f4SXin Li 							}
367*600f14f4SXin Li 						}
368*600f14f4SXin Li 						break;
369*600f14f4SXin Li 						case FLAC__METADATA_TYPE_CUESHEET:
370*600f14f4SXin Li 						{
371*600f14f4SXin Li 							uint32_t num_tracks, num_indices;
372*600f14f4SXin Li 							FLAC::Metadata::CueSheet * cuesheet = dynamic_cast<FLAC::Metadata::CueSheet *>(metadata_block_transfer);
373*600f14f4SXin Li 							if(cuesheet == 0 || !cuesheet->is_legal())
374*600f14f4SXin Li 								break;
375*600f14f4SXin Li 							num_tracks = cuesheet->get_num_tracks();
376*600f14f4SXin Li 							if(num_tracks > 0) {
377*600f14f4SXin Li 								FLAC::Metadata::CueSheet::Track track = cuesheet->get_track(min(data[i]>>4,num_tracks-1));
378*600f14f4SXin Li 								num_indices = track.get_num_indices();
379*600f14f4SXin Li 								if(num_indices > 0) {
380*600f14f4SXin Li 									FLAC__StreamMetadata_CueSheet_Index index = track.get_index(min(data[i]>>4,num_indices-1));
381*600f14f4SXin Li 									track.set_index(0,index);
382*600f14f4SXin Li 									cuesheet->insert_index(0,0,index);
383*600f14f4SXin Li 									cuesheet->insert_blank_index(0,0);
384*600f14f4SXin Li 								}
385*600f14f4SXin Li 								cuesheet->insert_blank_track(0);
386*600f14f4SXin Li 								cuesheet->insert_track(0,track);
387*600f14f4SXin Li 								cuesheet->resize_indices(min(data[i]>>4,num_tracks-1),data[i]>>4);
388*600f14f4SXin Li 							}
389*600f14f4SXin Li 						}
390*600f14f4SXin Li 						break;
391*600f14f4SXin Li 						case FLAC__METADATA_TYPE_PICTURE:
392*600f14f4SXin Li 						{
393*600f14f4SXin Li 							FLAC::Metadata::Picture * picture = dynamic_cast<FLAC::Metadata::Picture *>(metadata_block_transfer);
394*600f14f4SXin Li 							const char testtext[] = "TEST";
395*600f14f4SXin Li 							if(picture == 0 || !picture->is_legal(NULL))
396*600f14f4SXin Li 								break;
397*600f14f4SXin Li 							picture->set_description((FLAC__byte *)&testtext);
398*600f14f4SXin Li 							picture->set_mime_type((const char *)&testtext);
399*600f14f4SXin Li 							picture->set_data((FLAC__byte *)&testtext,4);
400*600f14f4SXin Li 						}
401*600f14f4SXin Li 						break;
402*600f14f4SXin Li 						default:
403*600f14f4SXin Li 						break;
404*600f14f4SXin Li 					}
405*600f14f4SXin Li 
406*600f14f4SXin Li 				}
407*600f14f4SXin Li 				break;
408*600f14f4SXin Li 			case 10: /* Delete from block */
409*600f14f4SXin Li 				if(metadata_block_transfer != 0 && metadata_block_transfer->is_valid()) {
410*600f14f4SXin Li 					switch(metadata_block_transfer->get_type()) {
411*600f14f4SXin Li 						case FLAC__METADATA_TYPE_SEEKTABLE:
412*600f14f4SXin Li 						{
413*600f14f4SXin Li 							uint32_t num_seekpoints;
414*600f14f4SXin Li 							FLAC::Metadata::SeekTable * seektable = dynamic_cast<FLAC::Metadata::SeekTable *>(metadata_block_transfer);
415*600f14f4SXin Li 							if(seektable == 0)
416*600f14f4SXin Li 								break;
417*600f14f4SXin Li 							if(seektable->is_valid() && seektable->is_legal()) {
418*600f14f4SXin Li 								num_seekpoints = seektable->get_num_points();
419*600f14f4SXin Li 								if(num_seekpoints > 0)
420*600f14f4SXin Li 									seektable->delete_point(min(data[i]>>4,num_seekpoints-1));
421*600f14f4SXin Li 							}
422*600f14f4SXin Li 						}
423*600f14f4SXin Li 						case FLAC__METADATA_TYPE_VORBIS_COMMENT:
424*600f14f4SXin Li 						{
425*600f14f4SXin Li 							uint32_t num_comments;
426*600f14f4SXin Li 							FLAC::Metadata::VorbisComment * vorbiscomment = dynamic_cast<FLAC::Metadata::VorbisComment *>(metadata_block_transfer);
427*600f14f4SXin Li 							if(vorbiscomment == 0)
428*600f14f4SXin Li 								break;
429*600f14f4SXin Li 							num_comments = vorbiscomment->get_num_comments();
430*600f14f4SXin Li 							if(num_comments > 0)
431*600f14f4SXin Li 								vorbiscomment->delete_comment(min(data[i]>>4,num_comments-1));
432*600f14f4SXin Li 							vorbiscomment->remove_entry_matching("TEST");
433*600f14f4SXin Li 							vorbiscomment->remove_entries_matching("TEST");
434*600f14f4SXin Li 						}
435*600f14f4SXin Li 						break;
436*600f14f4SXin Li 						case FLAC__METADATA_TYPE_CUESHEET:
437*600f14f4SXin Li 						{
438*600f14f4SXin Li 							uint32_t num_tracks;
439*600f14f4SXin Li 							FLAC::Metadata::CueSheet * cuesheet = dynamic_cast<FLAC::Metadata::CueSheet *>(metadata_block_transfer);
440*600f14f4SXin Li 							if(cuesheet == 0 || !cuesheet->is_legal())
441*600f14f4SXin Li 								break;
442*600f14f4SXin Li 							num_tracks = cuesheet->get_num_tracks();
443*600f14f4SXin Li 							if(num_tracks > 0) {
444*600f14f4SXin Li 								FLAC::Metadata::CueSheet::Track track = cuesheet->get_track(min(data[i]>>4,num_tracks-1));
445*600f14f4SXin Li 								if(track.get_num_indices() > 0)
446*600f14f4SXin Li 									cuesheet->delete_index(min(data[i]>>4,num_tracks-1),0);
447*600f14f4SXin Li 								cuesheet->delete_track(0);
448*600f14f4SXin Li 							}
449*600f14f4SXin Li 						}
450*600f14f4SXin Li 						break;
451*600f14f4SXin Li 						default:
452*600f14f4SXin Li 						break;
453*600f14f4SXin Li 					}
454*600f14f4SXin Li 
455*600f14f4SXin Li 				}
456*600f14f4SXin Li 				break;
457*600f14f4SXin Li 			case 11: /* Resize block */
458*600f14f4SXin Li 				if(metadata_block_transfer != 0 && metadata_block_transfer->is_valid()) {
459*600f14f4SXin Li 					switch(metadata_block_transfer->get_type()) {
460*600f14f4SXin Li 						case FLAC__METADATA_TYPE_PADDING:
461*600f14f4SXin Li 						{
462*600f14f4SXin Li 							FLAC::Metadata::Padding * padding = dynamic_cast<FLAC::Metadata::Padding *>(metadata_block_transfer);
463*600f14f4SXin Li 							if(padding == 0)
464*600f14f4SXin Li 								break;
465*600f14f4SXin Li 							padding->set_length(data[i]>>4);
466*600f14f4SXin Li 						}
467*600f14f4SXin Li 						break;
468*600f14f4SXin Li 						case FLAC__METADATA_TYPE_SEEKTABLE:
469*600f14f4SXin Li 						{
470*600f14f4SXin Li 							FLAC::Metadata::SeekTable * seektable = dynamic_cast<FLAC::Metadata::SeekTable *>(metadata_block_transfer);
471*600f14f4SXin Li 							if(seektable == 0)
472*600f14f4SXin Li 								break;
473*600f14f4SXin Li 							seektable->resize_points(data[i]>>4);
474*600f14f4SXin Li 						}
475*600f14f4SXin Li 						break;
476*600f14f4SXin Li 						case FLAC__METADATA_TYPE_VORBIS_COMMENT:
477*600f14f4SXin Li 						{
478*600f14f4SXin Li 							FLAC::Metadata::VorbisComment * vorbiscomment = dynamic_cast<FLAC::Metadata::VorbisComment *>(metadata_block_transfer);
479*600f14f4SXin Li 							if(vorbiscomment == 0)
480*600f14f4SXin Li 								break;
481*600f14f4SXin Li 							vorbiscomment->resize_comments(data[i]>>4);
482*600f14f4SXin Li 						}
483*600f14f4SXin Li 						break;
484*600f14f4SXin Li 						case FLAC__METADATA_TYPE_CUESHEET:
485*600f14f4SXin Li 						{
486*600f14f4SXin Li 							uint32_t num_tracks;
487*600f14f4SXin Li 							FLAC::Metadata::CueSheet * cuesheet = dynamic_cast<FLAC::Metadata::CueSheet *>(metadata_block_transfer);
488*600f14f4SXin Li 							if(cuesheet == 0 || !cuesheet->is_legal())
489*600f14f4SXin Li 								break;
490*600f14f4SXin Li 							num_tracks = cuesheet->get_num_tracks();
491*600f14f4SXin Li 							if(num_tracks > 0) {
492*600f14f4SXin Li 								cuesheet->resize_indices(min(data[i]>>4,num_tracks-1),data[i]>>4);
493*600f14f4SXin Li 							}
494*600f14f4SXin Li 							cuesheet->resize_tracks(data[i]<<4);
495*600f14f4SXin Li 						}
496*600f14f4SXin Li 						break;
497*600f14f4SXin Li 						default:
498*600f14f4SXin Li 						break;
499*600f14f4SXin Li 					}
500*600f14f4SXin Li 
501*600f14f4SXin Li 				}
502*600f14f4SXin Li 				break;
503*600f14f4SXin Li 			case 12: /* Prototype functions */
504*600f14f4SXin Li 				if(metadata_block_transfer != 0 && metadata_block_transfer->is_valid()) {
505*600f14f4SXin Li 					const ::FLAC__StreamMetadata * metadata_compare = *metadata_block_transfer;
506*600f14f4SXin Li 					metadata_block_transfer->get_is_last();
507*600f14f4SXin Li 					metadata_block_transfer->get_length();
508*600f14f4SXin Li 					metadata_block_transfer->set_is_last(data[i] & 16);
509*600f14f4SXin Li 					FLAC__metadata_object_is_equal(metadata_compare, metadata_compare);
510*600f14f4SXin Li 				}
511*600f14f4SXin Li 				break;
512*600f14f4SXin Li 		}
513*600f14f4SXin Li 	}
514*600f14f4SXin Li 	if(metadata_block_transfer != 0) {
515*600f14f4SXin Li 		delete metadata_block_transfer;
516*600f14f4SXin Li 		metadata_block_transfer = nullptr;
517*600f14f4SXin Li 	}
518*600f14f4SXin Li 
519*600f14f4SXin Li 	chain.status();
520*600f14f4SXin Li 	chain.sort_padding();
521*600f14f4SXin Li 	chain.merge_padding();
522*600f14f4SXin Li 
523*600f14f4SXin Li 	chain.check_if_tempfile_needed(!use_padding);
524*600f14f4SXin Li 	chain.write(use_padding);
525*600f14f4SXin Li 
526*600f14f4SXin Li }
527