1 /* test_libFLAC - Unit tester for libFLAC
2  * Copyright (C) 2002-2009  Josh Coalson
3  * Copyright (C) 2011-2016  Xiph.Org Foundation
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License
7  * as published by the Free Software Foundation; either version 2
8  * of the License, or (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License along
16  * with this program; if not, write to the Free Software Foundation, Inc.,
17  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18  */
19 
20 /*
21  * These are not tests, just utility functions used by the metadata tests
22  */
23 
24 #ifdef HAVE_CONFIG_H
25 #  include <config.h>
26 #endif
27 
28 #include "FLAC/metadata.h"
29 #include "test_libs_common/metadata_utils.h"
30 #include "share/compat.h"
31 #include <stdio.h>
32 #include <stdlib.h> /* for malloc() */
33 #include <string.h> /* for memcmp() */
34 
mutils__compare_block_data_streaminfo(const FLAC__StreamMetadata_StreamInfo * block,const FLAC__StreamMetadata_StreamInfo * blockcopy)35 FLAC__bool mutils__compare_block_data_streaminfo(const FLAC__StreamMetadata_StreamInfo *block, const FLAC__StreamMetadata_StreamInfo *blockcopy)
36 {
37 	if(blockcopy->min_blocksize != block->min_blocksize) {
38 		printf("FAILED, min_blocksize mismatch, expected %u, got %u\n", block->min_blocksize, blockcopy->min_blocksize);
39 		return false;
40 	}
41 	if(blockcopy->max_blocksize != block->max_blocksize) {
42 		printf("FAILED, max_blocksize mismatch, expected %u, got %u\n", block->max_blocksize, blockcopy->max_blocksize);
43 		return false;
44 	}
45 	if(blockcopy->min_framesize != block->min_framesize) {
46 		printf("FAILED, min_framesize mismatch, expected %u, got %u\n", block->min_framesize, blockcopy->min_framesize);
47 		return false;
48 	}
49 	if(blockcopy->max_framesize != block->max_framesize) {
50 		printf("FAILED, max_framesize mismatch, expected %u, got %u\n", block->max_framesize, blockcopy->max_framesize);
51 		return false;
52 	}
53 	if(blockcopy->sample_rate != block->sample_rate) {
54 		printf("FAILED, sample_rate mismatch, expected %u, got %u\n", block->sample_rate, blockcopy->sample_rate);
55 		return false;
56 	}
57 	if(blockcopy->channels != block->channels) {
58 		printf("FAILED, channels mismatch, expected %u, got %u\n", block->channels, blockcopy->channels);
59 		return false;
60 	}
61 	if(blockcopy->bits_per_sample != block->bits_per_sample) {
62 		printf("FAILED, bits_per_sample mismatch, expected %u, got %u\n", block->bits_per_sample, blockcopy->bits_per_sample);
63 		return false;
64 	}
65 	if(blockcopy->total_samples != block->total_samples) {
66 		printf("FAILED, total_samples mismatch, expected %" PRIu64 ", got %" PRIu64 "\n", block->total_samples, blockcopy->total_samples);
67 		return false;
68 	}
69 	if(0 != memcmp(blockcopy->md5sum, block->md5sum, sizeof(block->md5sum))) {
70 		printf("FAILED, md5sum mismatch, expected %02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X, got %02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X\n",
71 			(uint32_t)block->md5sum[0],
72 			(uint32_t)block->md5sum[1],
73 			(uint32_t)block->md5sum[2],
74 			(uint32_t)block->md5sum[3],
75 			(uint32_t)block->md5sum[4],
76 			(uint32_t)block->md5sum[5],
77 			(uint32_t)block->md5sum[6],
78 			(uint32_t)block->md5sum[7],
79 			(uint32_t)block->md5sum[8],
80 			(uint32_t)block->md5sum[9],
81 			(uint32_t)block->md5sum[10],
82 			(uint32_t)block->md5sum[11],
83 			(uint32_t)block->md5sum[12],
84 			(uint32_t)block->md5sum[13],
85 			(uint32_t)block->md5sum[14],
86 			(uint32_t)block->md5sum[15],
87 			(uint32_t)blockcopy->md5sum[0],
88 			(uint32_t)blockcopy->md5sum[1],
89 			(uint32_t)blockcopy->md5sum[2],
90 			(uint32_t)blockcopy->md5sum[3],
91 			(uint32_t)blockcopy->md5sum[4],
92 			(uint32_t)blockcopy->md5sum[5],
93 			(uint32_t)blockcopy->md5sum[6],
94 			(uint32_t)blockcopy->md5sum[7],
95 			(uint32_t)blockcopy->md5sum[8],
96 			(uint32_t)blockcopy->md5sum[9],
97 			(uint32_t)blockcopy->md5sum[10],
98 			(uint32_t)blockcopy->md5sum[11],
99 			(uint32_t)blockcopy->md5sum[12],
100 			(uint32_t)blockcopy->md5sum[13],
101 			(uint32_t)blockcopy->md5sum[14],
102 			(uint32_t)blockcopy->md5sum[15]
103 		);
104 		return false;
105 	}
106 	return true;
107 }
108 
mutils__compare_block_data_padding(const FLAC__StreamMetadata_Padding * block,const FLAC__StreamMetadata_Padding * blockcopy,uint32_t block_length)109 FLAC__bool mutils__compare_block_data_padding(const FLAC__StreamMetadata_Padding *block, const FLAC__StreamMetadata_Padding *blockcopy, uint32_t block_length)
110 {
111 	/* we don't compare the padding guts */
112 	(void)block, (void)blockcopy, (void)block_length;
113 	return true;
114 }
115 
mutils__compare_block_data_application(const FLAC__StreamMetadata_Application * block,const FLAC__StreamMetadata_Application * blockcopy,uint32_t block_length)116 FLAC__bool mutils__compare_block_data_application(const FLAC__StreamMetadata_Application *block, const FLAC__StreamMetadata_Application *blockcopy, uint32_t block_length)
117 {
118 	if(block_length < sizeof(block->id)) {
119 		printf("FAILED, bad block length = %u\n", block_length);
120 		return false;
121 	}
122 	if(0 != memcmp(blockcopy->id, block->id, sizeof(block->id))) {
123 		printf("FAILED, id mismatch, expected %02X%02X%02X%02X, got %02X%02X%02X%02X\n",
124 			(uint32_t)block->id[0],
125 			(uint32_t)block->id[1],
126 			(uint32_t)block->id[2],
127 			(uint32_t)block->id[3],
128 			(uint32_t)blockcopy->id[0],
129 			(uint32_t)blockcopy->id[1],
130 			(uint32_t)blockcopy->id[2],
131 			(uint32_t)blockcopy->id[3]
132 		);
133 		return false;
134 	}
135 	if(0 == block->data || 0 == blockcopy->data) {
136 		if(block->data != blockcopy->data) {
137 			printf("FAILED, data mismatch (%s's data pointer is null)\n", 0==block->data?"original":"copy");
138 			return false;
139 		}
140 		else if(block_length - sizeof(block->id) > 0) {
141 			printf("FAILED, data pointer is null but block length is not 0\n");
142 			return false;
143 		}
144 	}
145 	else {
146 		if(block_length - sizeof(block->id) == 0) {
147 			printf("FAILED, data pointer is not null but block length is 0\n");
148 			return false;
149 		}
150 		else if(0 != memcmp(blockcopy->data, block->data, block_length - sizeof(block->id))) {
151 			printf("FAILED, data mismatch\n");
152 			return false;
153 		}
154 	}
155 	return true;
156 }
157 
mutils__compare_block_data_seektable(const FLAC__StreamMetadata_SeekTable * block,const FLAC__StreamMetadata_SeekTable * blockcopy)158 FLAC__bool mutils__compare_block_data_seektable(const FLAC__StreamMetadata_SeekTable *block, const FLAC__StreamMetadata_SeekTable *blockcopy)
159 {
160 	uint32_t i;
161 	if(blockcopy->num_points != block->num_points) {
162 		printf("FAILED, num_points mismatch, expected %u, got %u\n", block->num_points, blockcopy->num_points);
163 		return false;
164 	}
165 	for(i = 0; i < block->num_points; i++) {
166 		if(blockcopy->points[i].sample_number != block->points[i].sample_number) {
167 			printf("FAILED, points[%u].sample_number mismatch, expected %" PRIu64 ", got %" PRIu64 "\n", i, block->points[i].sample_number, blockcopy->points[i].sample_number);
168 			return false;
169 		}
170 		if(blockcopy->points[i].stream_offset != block->points[i].stream_offset) {
171 			printf("FAILED, points[%u].stream_offset mismatch, expected %" PRIu64 ", got %" PRIu64 "\n", i, block->points[i].stream_offset, blockcopy->points[i].stream_offset);
172 			return false;
173 		}
174 		if(blockcopy->points[i].frame_samples != block->points[i].frame_samples) {
175 			printf("FAILED, points[%u].frame_samples mismatch, expected %u, got %u\n", i, block->points[i].frame_samples, blockcopy->points[i].frame_samples);
176 			return false;
177 		}
178 	}
179 	return true;
180 }
181 
mutils__compare_block_data_vorbiscomment(const FLAC__StreamMetadata_VorbisComment * block,const FLAC__StreamMetadata_VorbisComment * blockcopy)182 FLAC__bool mutils__compare_block_data_vorbiscomment(const FLAC__StreamMetadata_VorbisComment *block, const FLAC__StreamMetadata_VorbisComment *blockcopy)
183 {
184 	uint32_t i;
185 	if(blockcopy->vendor_string.length != block->vendor_string.length) {
186 		printf("FAILED, vendor_string.length mismatch, expected %u, got %u\n", block->vendor_string.length, blockcopy->vendor_string.length);
187 		return false;
188 	}
189 	if(0 == block->vendor_string.entry || 0 == blockcopy->vendor_string.entry) {
190 		if(block->vendor_string.entry != blockcopy->vendor_string.entry) {
191 			printf("FAILED, vendor_string.entry mismatch\n");
192 			return false;
193 		}
194 	}
195 	else if(0 != memcmp(blockcopy->vendor_string.entry, block->vendor_string.entry, block->vendor_string.length)) {
196 		printf("FAILED, vendor_string.entry mismatch\n");
197 		return false;
198 	}
199 	if(blockcopy->num_comments != block->num_comments) {
200 		printf("FAILED, num_comments mismatch, expected %u, got %u\n", block->num_comments, blockcopy->num_comments);
201 		return false;
202 	}
203 	for(i = 0; i < block->num_comments; i++) {
204 		if(blockcopy->comments[i].length != block->comments[i].length) {
205 			printf("FAILED, comments[%u].length mismatch, expected %u, got %u\n", i, block->comments[i].length, blockcopy->comments[i].length);
206 			return false;
207 		}
208 		if(0 == block->comments[i].entry || 0 == blockcopy->comments[i].entry) {
209 			if(block->comments[i].entry != blockcopy->comments[i].entry) {
210 				printf("FAILED, comments[%u].entry mismatch\n", i);
211 				return false;
212 			}
213 		}
214 		else {
215 			if(0 != memcmp(blockcopy->comments[i].entry, block->comments[i].entry, block->comments[i].length)) {
216 				printf("FAILED, comments[%u].entry mismatch\n", i);
217 				return false;
218 			}
219 		}
220 	}
221 	return true;
222 }
223 
mutils__compare_block_data_cuesheet(const FLAC__StreamMetadata_CueSheet * block,const FLAC__StreamMetadata_CueSheet * blockcopy)224 FLAC__bool mutils__compare_block_data_cuesheet(const FLAC__StreamMetadata_CueSheet *block, const FLAC__StreamMetadata_CueSheet *blockcopy)
225 {
226 	uint32_t i, j;
227 
228 	if(0 != strcmp(blockcopy->media_catalog_number, block->media_catalog_number)) {
229 		printf("FAILED, media_catalog_number mismatch, expected %s, got %s\n", block->media_catalog_number, blockcopy->media_catalog_number);
230 		return false;
231 	}
232 	if(blockcopy->lead_in != block->lead_in) {
233 		printf("FAILED, lead_in mismatch, expected %" PRIu64 ", got %" PRIu64 "\n", block->lead_in, blockcopy->lead_in);
234 		return false;
235 	}
236 	if(blockcopy->is_cd != block->is_cd) {
237 		printf("FAILED, is_cd mismatch, expected %u, got %u\n", (uint32_t)block->is_cd, (uint32_t)blockcopy->is_cd);
238 		return false;
239 	}
240 	if(blockcopy->num_tracks != block->num_tracks) {
241 		printf("FAILED, num_tracks mismatch, expected %u, got %u\n", block->num_tracks, blockcopy->num_tracks);
242 		return false;
243 	}
244 	for(i = 0; i < block->num_tracks; i++) {
245 		if(blockcopy->tracks[i].offset != block->tracks[i].offset) {
246 			printf("FAILED, tracks[%u].offset mismatch, expected %" PRIu64 ", got %" PRIu64 "\n", i, block->tracks[i].offset, blockcopy->tracks[i].offset);
247 			return false;
248 		}
249 		if(blockcopy->tracks[i].number != block->tracks[i].number) {
250 			printf("FAILED, tracks[%u].number mismatch, expected %u, got %u\n", i, (uint32_t)block->tracks[i].number, (uint32_t)blockcopy->tracks[i].number);
251 			return false;
252 		}
253 		if(blockcopy->tracks[i].num_indices != block->tracks[i].num_indices) {
254 			printf("FAILED, tracks[%u].num_indices mismatch, expected %u, got %u\n", i, (uint32_t)block->tracks[i].num_indices, (uint32_t)blockcopy->tracks[i].num_indices);
255 			return false;
256 		}
257 		/* num_indices == 0 means lead-out track so only the track offset and number are valid */
258 		if(block->tracks[i].num_indices > 0) {
259 			if(0 != strcmp(blockcopy->tracks[i].isrc, block->tracks[i].isrc)) {
260 				printf("FAILED, tracks[%u].isrc mismatch, expected %s, got %s\n", i, block->tracks[i].isrc, blockcopy->tracks[i].isrc);
261 				return false;
262 			}
263 			if(blockcopy->tracks[i].type != block->tracks[i].type) {
264 				printf("FAILED, tracks[%u].type mismatch, expected %u, got %u\n", i, (uint32_t)block->tracks[i].type, (uint32_t)blockcopy->tracks[i].type);
265 				return false;
266 			}
267 			if(blockcopy->tracks[i].pre_emphasis != block->tracks[i].pre_emphasis) {
268 				printf("FAILED, tracks[%u].pre_emphasis mismatch, expected %u, got %u\n", i, (uint32_t)block->tracks[i].pre_emphasis, (uint32_t)blockcopy->tracks[i].pre_emphasis);
269 				return false;
270 			}
271 			if(0 == block->tracks[i].indices || 0 == blockcopy->tracks[i].indices) {
272 				if(block->tracks[i].indices != blockcopy->tracks[i].indices) {
273 					printf("FAILED, tracks[%u].indices mismatch\n", i);
274 					return false;
275 				}
276 			}
277 			else {
278 				for(j = 0; j < block->tracks[i].num_indices; j++) {
279 					if(blockcopy->tracks[i].indices[j].offset != block->tracks[i].indices[j].offset) {
280 						printf("FAILED, tracks[%u].indices[%u].offset mismatch, expected %" PRIu64 ", got %" PRIu64 "\n", i, j, block->tracks[i].indices[j].offset, blockcopy->tracks[i].indices[j].offset);
281 						return false;
282 					}
283 					if(blockcopy->tracks[i].indices[j].number != block->tracks[i].indices[j].number) {
284 						printf("FAILED, tracks[%u].indices[%u].number mismatch, expected %u, got %u\n", i, j, (uint32_t)block->tracks[i].indices[j].number, (uint32_t)blockcopy->tracks[i].indices[j].number);
285 						return false;
286 					}
287 				}
288 			}
289 		}
290 	}
291 	return true;
292 }
293 
mutils__compare_block_data_picture(const FLAC__StreamMetadata_Picture * block,const FLAC__StreamMetadata_Picture * blockcopy)294 FLAC__bool mutils__compare_block_data_picture(const FLAC__StreamMetadata_Picture *block, const FLAC__StreamMetadata_Picture *blockcopy)
295 {
296 	size_t len, lencopy;
297 	if(blockcopy->type != block->type) {
298 		printf("FAILED, type mismatch, expected %u, got %u\n", (uint32_t)block->type, (uint32_t)blockcopy->type);
299 		return false;
300 	}
301 	len = strlen(block->mime_type);
302 	lencopy = strlen(blockcopy->mime_type);
303 	if(lencopy != len) {
304 		printf("FAILED, mime_type length mismatch, expected %u, got %u\n", (uint32_t)len, (uint32_t)lencopy);
305 		return false;
306 	}
307 	if(strcmp(blockcopy->mime_type, block->mime_type)) {
308 		printf("FAILED, mime_type mismatch, expected %s, got %s\n", block->mime_type, blockcopy->mime_type);
309 		return false;
310 	}
311 	len = strlen((const char *)block->description);
312 	lencopy = strlen((const char *)blockcopy->description);
313 	if(lencopy != len) {
314 		printf("FAILED, description length mismatch, expected %u, got %u\n", (uint32_t)len, (uint32_t)lencopy);
315 		return false;
316 	}
317 	if(strcmp((const char *)blockcopy->description, (const char *)block->description)) {
318 		printf("FAILED, description mismatch, expected %s, got %s\n", block->description, blockcopy->description);
319 		return false;
320 	}
321 	if(blockcopy->width != block->width) {
322 		printf("FAILED, width mismatch, expected %u, got %u\n", block->width, blockcopy->width);
323 		return false;
324 	}
325 	if(blockcopy->height != block->height) {
326 		printf("FAILED, height mismatch, expected %u, got %u\n", block->height, blockcopy->height);
327 		return false;
328 	}
329 	if(blockcopy->depth != block->depth) {
330 		printf("FAILED, depth mismatch, expected %u, got %u\n", block->depth, blockcopy->depth);
331 		return false;
332 	}
333 	if(blockcopy->colors != block->colors) {
334 		printf("FAILED, colors mismatch, expected %u, got %u\n", block->colors, blockcopy->colors);
335 		return false;
336 	}
337 	if(blockcopy->data_length != block->data_length) {
338 		printf("FAILED, data_length mismatch, expected %u, got %u\n", block->data_length, blockcopy->data_length);
339 		return false;
340 	}
341 	if(block->data_length > 0 && memcmp(blockcopy->data, block->data, block->data_length)) {
342 		printf("FAILED, data mismatch\n");
343 		return false;
344 	}
345 	return true;
346 }
347 
mutils__compare_block_data_unknown(const FLAC__StreamMetadata_Unknown * block,const FLAC__StreamMetadata_Unknown * blockcopy,uint32_t block_length)348 FLAC__bool mutils__compare_block_data_unknown(const FLAC__StreamMetadata_Unknown *block, const FLAC__StreamMetadata_Unknown *blockcopy, uint32_t block_length)
349 {
350 	if(0 == block->data || 0 == blockcopy->data) {
351 		if(block->data != blockcopy->data) {
352 			printf("FAILED, data mismatch (%s's data pointer is null)\n", 0==block->data?"original":"copy");
353 			return false;
354 		}
355 		else if(block_length > 0) {
356 			printf("FAILED, data pointer is null but block length is not 0\n");
357 			return false;
358 		}
359 	}
360 	else {
361 		if(block_length == 0) {
362 			printf("FAILED, data pointer is not null but block length is 0\n");
363 			return false;
364 		}
365 		else if(0 != memcmp(blockcopy->data, block->data, block_length)) {
366 			printf("FAILED, data mismatch\n");
367 			return false;
368 		}
369 	}
370 	return true;
371 }
372 
mutils__compare_block(const FLAC__StreamMetadata * block,const FLAC__StreamMetadata * blockcopy)373 FLAC__bool mutils__compare_block(const FLAC__StreamMetadata *block, const FLAC__StreamMetadata *blockcopy)
374 {
375 	if(blockcopy->type != block->type) {
376 		printf("FAILED, type mismatch, expected %s, got %s\n", FLAC__MetadataTypeString[block->type], FLAC__MetadataTypeString[blockcopy->type]);
377 		return false;
378 	}
379 	if(blockcopy->is_last != block->is_last) {
380 		printf("FAILED, is_last mismatch, expected %u, got %u\n", (uint32_t)block->is_last, (uint32_t)blockcopy->is_last);
381 		return false;
382 	}
383 	if(blockcopy->length != block->length) {
384 		printf("FAILED, length mismatch, expected %u, got %u\n", block->length, blockcopy->length);
385 		return false;
386 	}
387 	switch(block->type) {
388 		case FLAC__METADATA_TYPE_STREAMINFO:
389 			return mutils__compare_block_data_streaminfo(&block->data.stream_info, &blockcopy->data.stream_info);
390 		case FLAC__METADATA_TYPE_PADDING:
391 			return mutils__compare_block_data_padding(&block->data.padding, &blockcopy->data.padding, block->length);
392 		case FLAC__METADATA_TYPE_APPLICATION:
393 			return mutils__compare_block_data_application(&block->data.application, &blockcopy->data.application, block->length);
394 		case FLAC__METADATA_TYPE_SEEKTABLE:
395 			return mutils__compare_block_data_seektable(&block->data.seek_table, &blockcopy->data.seek_table);
396 		case FLAC__METADATA_TYPE_VORBIS_COMMENT:
397 			return mutils__compare_block_data_vorbiscomment(&block->data.vorbis_comment, &blockcopy->data.vorbis_comment);
398 		case FLAC__METADATA_TYPE_CUESHEET:
399 			return mutils__compare_block_data_cuesheet(&block->data.cue_sheet, &blockcopy->data.cue_sheet);
400 		case FLAC__METADATA_TYPE_PICTURE:
401 			return mutils__compare_block_data_picture(&block->data.picture, &blockcopy->data.picture);
402 		default:
403 			return mutils__compare_block_data_unknown(&block->data.unknown, &blockcopy->data.unknown, block->length);
404 	}
405 }
406 
malloc_or_die_(size_t size)407 static void *malloc_or_die_(size_t size)
408 {
409 	void *x = malloc(size);
410 	if(0 == x) {
411 		fprintf(stderr, "ERROR: out of memory allocating %u bytes\n", (uint32_t)size);
412 		exit(1);
413 	}
414 	return x;
415 }
416 
calloc_or_die_(size_t n,size_t size)417 static void *calloc_or_die_(size_t n, size_t size)
418 {
419 	void *x = calloc(n, size);
420 	if(0 == x) {
421 		fprintf(stderr, "ERROR: out of memory allocating %u bytes\n", (uint32_t)n * (uint32_t)size);
422 		exit(1);
423 	}
424 	return x;
425 }
426 
strdup_or_die_(const char * s)427 static char *strdup_or_die_(const char *s)
428 {
429 	char *x = strdup(s);
430 	if(0 == x) {
431 		fprintf(stderr, "ERROR: out of memory copying string \"%s\"\n", s);
432 		exit(1);
433 	}
434 	return x;
435 }
436 
mutils__init_metadata_blocks(FLAC__StreamMetadata * streaminfo,FLAC__StreamMetadata * padding,FLAC__StreamMetadata * seektable,FLAC__StreamMetadata * application1,FLAC__StreamMetadata * application2,FLAC__StreamMetadata * vorbiscomment,FLAC__StreamMetadata * cuesheet,FLAC__StreamMetadata * picture,FLAC__StreamMetadata * unknown)437 void mutils__init_metadata_blocks(
438 	FLAC__StreamMetadata *streaminfo,
439 	FLAC__StreamMetadata *padding,
440 	FLAC__StreamMetadata *seektable,
441 	FLAC__StreamMetadata *application1,
442 	FLAC__StreamMetadata *application2,
443 	FLAC__StreamMetadata *vorbiscomment,
444 	FLAC__StreamMetadata *cuesheet,
445 	FLAC__StreamMetadata *picture,
446 	FLAC__StreamMetadata *unknown
447 )
448 {
449 	/*
450 		most of the actual numbers and data in the blocks don't matter,
451 		we just want to make sure the decoder parses them correctly
452 
453 		remember, the metadata interface gets tested after the decoders,
454 		so we do all the metadata manipulation here without it.
455 	*/
456 
457 	/* min/max_framesize and md5sum don't get written at first, so we have to leave them 0 */
458 	streaminfo->is_last = false;
459 	streaminfo->type = FLAC__METADATA_TYPE_STREAMINFO;
460 	streaminfo->length = FLAC__STREAM_METADATA_STREAMINFO_LENGTH;
461 	streaminfo->data.stream_info.min_blocksize = 576;
462 	streaminfo->data.stream_info.max_blocksize = 576;
463 	streaminfo->data.stream_info.min_framesize = 0;
464 	streaminfo->data.stream_info.max_framesize = 0;
465 	streaminfo->data.stream_info.sample_rate = 44100;
466 	streaminfo->data.stream_info.channels = 1;
467 	streaminfo->data.stream_info.bits_per_sample = 8;
468 	streaminfo->data.stream_info.total_samples = 0;
469 	memset(streaminfo->data.stream_info.md5sum, 0, 16);
470 
471 	padding->is_last = false;
472 	padding->type = FLAC__METADATA_TYPE_PADDING;
473 	padding->length = 1234;
474 
475 	seektable->is_last = false;
476 	seektable->type = FLAC__METADATA_TYPE_SEEKTABLE;
477 	seektable->data.seek_table.num_points = 2;
478 	seektable->length = seektable->data.seek_table.num_points * FLAC__STREAM_METADATA_SEEKPOINT_LENGTH;
479 	seektable->data.seek_table.points = malloc_or_die_(seektable->data.seek_table.num_points * sizeof(FLAC__StreamMetadata_SeekPoint));
480 	seektable->data.seek_table.points[0].sample_number = 0;
481 	seektable->data.seek_table.points[0].stream_offset = 0;
482 	seektable->data.seek_table.points[0].frame_samples = streaminfo->data.stream_info.min_blocksize;
483 	seektable->data.seek_table.points[1].sample_number = FLAC__STREAM_METADATA_SEEKPOINT_PLACEHOLDER;
484 	seektable->data.seek_table.points[1].stream_offset = 1000;
485 	seektable->data.seek_table.points[1].frame_samples = streaminfo->data.stream_info.min_blocksize;
486 
487 	application1->is_last = false;
488 	application1->type = FLAC__METADATA_TYPE_APPLICATION;
489 	application1->length = 8;
490 	memcpy(application1->data.application.id, "This", 4);
491 	application1->data.application.data = malloc_or_die_(4);
492 	memcpy(application1->data.application.data, "\xf0\xe1\xd2\xc3", 4);
493 
494 	application2->is_last = false;
495 	application2->type = FLAC__METADATA_TYPE_APPLICATION;
496 	application2->length = 4;
497 	memcpy(application2->data.application.id, "Here", 4);
498 	application2->data.application.data = 0;
499 
500 	{
501 		const uint32_t vendor_string_length = (uint32_t)strlen(FLAC__VENDOR_STRING);
502 		vorbiscomment->is_last = false;
503 		vorbiscomment->type = FLAC__METADATA_TYPE_VORBIS_COMMENT;
504 		vorbiscomment->length = (4 + vendor_string_length) + 4 + (4 + 5) + (4 + 0);
505 		vorbiscomment->data.vorbis_comment.vendor_string.length = vendor_string_length;
506 		vorbiscomment->data.vorbis_comment.vendor_string.entry = malloc_or_die_(vendor_string_length+1);
507 		memcpy(vorbiscomment->data.vorbis_comment.vendor_string.entry, FLAC__VENDOR_STRING, vendor_string_length+1);
508 		vorbiscomment->data.vorbis_comment.num_comments = 2;
509 		vorbiscomment->data.vorbis_comment.comments = malloc_or_die_(vorbiscomment->data.vorbis_comment.num_comments * sizeof(FLAC__StreamMetadata_VorbisComment_Entry));
510 		vorbiscomment->data.vorbis_comment.comments[0].length = 5;
511 		vorbiscomment->data.vorbis_comment.comments[0].entry = malloc_or_die_(5+1);
512 		memcpy(vorbiscomment->data.vorbis_comment.comments[0].entry, "ab=cd", 5+1);
513 		vorbiscomment->data.vorbis_comment.comments[1].length = 0;
514 		vorbiscomment->data.vorbis_comment.comments[1].entry = 0;
515 	}
516 
517 	cuesheet->is_last = false;
518 	cuesheet->type = FLAC__METADATA_TYPE_CUESHEET;
519 	cuesheet->length =
520 		/* cuesheet guts */
521 		(
522 			FLAC__STREAM_METADATA_CUESHEET_MEDIA_CATALOG_NUMBER_LEN +
523 			FLAC__STREAM_METADATA_CUESHEET_LEAD_IN_LEN +
524 			FLAC__STREAM_METADATA_CUESHEET_IS_CD_LEN +
525 			FLAC__STREAM_METADATA_CUESHEET_RESERVED_LEN +
526 			FLAC__STREAM_METADATA_CUESHEET_NUM_TRACKS_LEN
527 		) / 8 +
528 		/* 2 tracks */
529 		3 * (
530 			FLAC__STREAM_METADATA_CUESHEET_TRACK_OFFSET_LEN +
531 			FLAC__STREAM_METADATA_CUESHEET_TRACK_NUMBER_LEN +
532 			FLAC__STREAM_METADATA_CUESHEET_TRACK_ISRC_LEN +
533 			FLAC__STREAM_METADATA_CUESHEET_TRACK_TYPE_LEN +
534 			FLAC__STREAM_METADATA_CUESHEET_TRACK_PRE_EMPHASIS_LEN +
535 			FLAC__STREAM_METADATA_CUESHEET_TRACK_RESERVED_LEN +
536 			FLAC__STREAM_METADATA_CUESHEET_TRACK_NUM_INDICES_LEN
537 		) / 8 +
538 		/* 3 index points */
539 		3 * (
540 			FLAC__STREAM_METADATA_CUESHEET_INDEX_OFFSET_LEN +
541 			FLAC__STREAM_METADATA_CUESHEET_INDEX_NUMBER_LEN +
542 			FLAC__STREAM_METADATA_CUESHEET_INDEX_RESERVED_LEN
543 		) / 8
544 	;
545 	memset(cuesheet->data.cue_sheet.media_catalog_number, 0, sizeof(cuesheet->data.cue_sheet.media_catalog_number));
546 	cuesheet->data.cue_sheet.media_catalog_number[0] = 'j';
547 	cuesheet->data.cue_sheet.media_catalog_number[1] = 'C';
548 	cuesheet->data.cue_sheet.lead_in = 2 * 44100;
549 	cuesheet->data.cue_sheet.is_cd = true;
550 	cuesheet->data.cue_sheet.num_tracks = 3;
551 	cuesheet->data.cue_sheet.tracks = calloc_or_die_(cuesheet->data.cue_sheet.num_tracks, sizeof(FLAC__StreamMetadata_CueSheet_Track));
552 	cuesheet->data.cue_sheet.tracks[0].offset = 0;
553 	cuesheet->data.cue_sheet.tracks[0].number = 1;
554 	memcpy(cuesheet->data.cue_sheet.tracks[0].isrc, "ACBDE1234567", sizeof(cuesheet->data.cue_sheet.tracks[0].isrc));
555 	cuesheet->data.cue_sheet.tracks[0].type = 0;
556 	cuesheet->data.cue_sheet.tracks[0].pre_emphasis = 1;
557 	cuesheet->data.cue_sheet.tracks[0].num_indices = 2;
558 	cuesheet->data.cue_sheet.tracks[0].indices = malloc_or_die_(cuesheet->data.cue_sheet.tracks[0].num_indices * sizeof(FLAC__StreamMetadata_CueSheet_Index));
559 	cuesheet->data.cue_sheet.tracks[0].indices[0].offset = 0;
560 	cuesheet->data.cue_sheet.tracks[0].indices[0].number = 0;
561 	cuesheet->data.cue_sheet.tracks[0].indices[1].offset = 123 * 588;
562 	cuesheet->data.cue_sheet.tracks[0].indices[1].number = 1;
563 	cuesheet->data.cue_sheet.tracks[1].offset = 1234 * 588;
564 	cuesheet->data.cue_sheet.tracks[1].number = 2;
565 	memcpy(cuesheet->data.cue_sheet.tracks[1].isrc, "ACBDE7654321", sizeof(cuesheet->data.cue_sheet.tracks[1].isrc));
566 	cuesheet->data.cue_sheet.tracks[1].type = 1;
567 	cuesheet->data.cue_sheet.tracks[1].pre_emphasis = 0;
568 	cuesheet->data.cue_sheet.tracks[1].num_indices = 1;
569 	cuesheet->data.cue_sheet.tracks[1].indices = malloc_or_die_(cuesheet->data.cue_sheet.tracks[1].num_indices * sizeof(FLAC__StreamMetadata_CueSheet_Index));
570 	cuesheet->data.cue_sheet.tracks[1].indices[0].offset = 0;
571 	cuesheet->data.cue_sheet.tracks[1].indices[0].number = 1;
572 	cuesheet->data.cue_sheet.tracks[2].offset = 12345 * 588;
573 	cuesheet->data.cue_sheet.tracks[2].number = 170;
574 	cuesheet->data.cue_sheet.tracks[2].num_indices = 0;
575 
576 	picture->is_last = false;
577 	picture->type = FLAC__METADATA_TYPE_PICTURE;
578 	picture->length =
579 		(
580 			FLAC__STREAM_METADATA_PICTURE_TYPE_LEN +
581 			FLAC__STREAM_METADATA_PICTURE_MIME_TYPE_LENGTH_LEN + /* will add the length for the string later */
582 			FLAC__STREAM_METADATA_PICTURE_DESCRIPTION_LENGTH_LEN + /* will add the length for the string later */
583 			FLAC__STREAM_METADATA_PICTURE_WIDTH_LEN +
584 			FLAC__STREAM_METADATA_PICTURE_HEIGHT_LEN +
585 			FLAC__STREAM_METADATA_PICTURE_DEPTH_LEN +
586 			FLAC__STREAM_METADATA_PICTURE_COLORS_LEN +
587 			FLAC__STREAM_METADATA_PICTURE_DATA_LENGTH_LEN /* will add the length for the data later */
588 		) / 8
589 	;
590 	picture->data.picture.type = FLAC__STREAM_METADATA_PICTURE_TYPE_FRONT_COVER;
591 	picture->data.picture.mime_type = strdup_or_die_("image/jpeg");
592 	picture->length += strlen(picture->data.picture.mime_type);
593 	picture->data.picture.description = (FLAC__byte*)strdup_or_die_("desc");
594 	picture->length += strlen((const char *)picture->data.picture.description);
595 	picture->data.picture.width = 300;
596 	picture->data.picture.height = 300;
597 	picture->data.picture.depth = 24;
598 	picture->data.picture.colors = 0;
599 	picture->data.picture.data = (FLAC__byte*)strdup_or_die_("SOMEJPEGDATA");
600 	picture->data.picture.data_length = strlen((const char *)picture->data.picture.data);
601 	picture->length += picture->data.picture.data_length;
602 
603 	unknown->is_last = true;
604 	unknown->type = 126;
605 	unknown->length = 8;
606 	unknown->data.unknown.data = malloc_or_die_(unknown->length);
607 	memcpy(unknown->data.unknown.data, "\xfe\xdc\xba\x98\xf0\xe1\xd2\xc3", unknown->length);
608 }
609 
mutils__free_metadata_blocks(FLAC__StreamMetadata * streaminfo,FLAC__StreamMetadata * padding,FLAC__StreamMetadata * seektable,FLAC__StreamMetadata * application1,FLAC__StreamMetadata * application2,FLAC__StreamMetadata * vorbiscomment,FLAC__StreamMetadata * cuesheet,FLAC__StreamMetadata * picture,FLAC__StreamMetadata * unknown)610 void mutils__free_metadata_blocks(
611 	FLAC__StreamMetadata *streaminfo,
612 	FLAC__StreamMetadata *padding,
613 	FLAC__StreamMetadata *seektable,
614 	FLAC__StreamMetadata *application1,
615 	FLAC__StreamMetadata *application2,
616 	FLAC__StreamMetadata *vorbiscomment,
617 	FLAC__StreamMetadata *cuesheet,
618 	FLAC__StreamMetadata *picture,
619 	FLAC__StreamMetadata *unknown
620 )
621 {
622 	(void)streaminfo, (void)padding, (void)application2;
623 	free(seektable->data.seek_table.points);
624 	free(application1->data.application.data);
625 	free(vorbiscomment->data.vorbis_comment.vendor_string.entry);
626 	free(vorbiscomment->data.vorbis_comment.comments[0].entry);
627 	free(vorbiscomment->data.vorbis_comment.comments);
628 	free(cuesheet->data.cue_sheet.tracks[0].indices);
629 	free(cuesheet->data.cue_sheet.tracks[1].indices);
630 	free(cuesheet->data.cue_sheet.tracks);
631 	free(picture->data.picture.mime_type);
632 	free(picture->data.picture.description);
633 	free(picture->data.picture.data);
634 	free(unknown->data.unknown.data);
635 }
636