xref: /aosp_15_r20/external/flac/src/flac/foreign_metadata.c (revision 600f14f40d737144c998e2ec7a483122d3776fbc)
1 /* flac - Command-line FLAC encoder/decoder
2  * Copyright (C) 2000-2009  Josh Coalson
3  * Copyright (C) 2011-2023  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 #ifdef HAVE_CONFIG_H
21 #  include <config.h>
22 #endif
23 
24 #include <stdio.h> /* for FILE etc. */
25 #include <stdlib.h> /* for calloc() etc. */
26 #include <string.h> /* for memcmp() etc. */
27 #include "FLAC/assert.h"
28 #include "FLAC/metadata.h"
29 #include "share/alloc.h"
30 #include "share/compat.h"
31 #include "foreign_metadata.h"
32 
33 #ifdef min
34 #undef min
35 #endif
36 #define min(x,y) ((x)<(y)?(x):(y))
37 
38 const char *FLAC__FOREIGN_METADATA_APPLICATION_ID[FLAC__FOREIGN_METADATA_NUMBER_OF_RECOGNIZED_APPLICATION_IDS] = { "aiff" , "riff", "w64 " };
39 
unpack32be_(const FLAC__byte * b)40 static FLAC__uint32 unpack32be_(const FLAC__byte *b)
41 {
42 	return ((FLAC__uint32)b[0]<<24) + ((FLAC__uint32)b[1]<<16) + ((FLAC__uint32)b[2]<<8) + (FLAC__uint32)b[3];
43 }
44 
unpack32le_(const FLAC__byte * b)45 static FLAC__uint32 unpack32le_(const FLAC__byte *b)
46 {
47 	return (FLAC__uint32)b[0] + ((FLAC__uint32)b[1]<<8) + ((FLAC__uint32)b[2]<<16) + ((FLAC__uint32)b[3]<<24);
48 }
49 
unpack64le_(const FLAC__byte * b)50 static FLAC__uint64 unpack64le_(const FLAC__byte *b)
51 {
52 	return (FLAC__uint64)b[0] + ((FLAC__uint64)b[1]<<8) + ((FLAC__uint64)b[2]<<16) + ((FLAC__uint64)b[3]<<24) + ((FLAC__uint64)b[4]<<32) + ((FLAC__uint64)b[5]<<40) + ((FLAC__uint64)b[6]<<48) + ((FLAC__uint64)b[7]<<56);
53 }
54 
55 /* copies 'size' bytes from file 'fin' to 'fout', filling in *error with 'read_error' or 'write_error' as necessary */
copy_data_(FILE * fin,FILE * fout,size_t size,const char ** error,const char * const read_error,const char * const write_error)56 static FLAC__bool copy_data_(FILE *fin, FILE *fout, size_t size, const char **error, const char * const read_error, const char * const write_error)
57 {
58 	FLAC__byte buffer[4096];
59 	size_t left;
60 	for(left = size; left > 0; ) {
61 		size_t need = min(sizeof(buffer), left);
62 		if(fread(buffer, 1, need, fin) < need) {
63 			if(error) *error = read_error;
64 			return false;
65 		}
66 		if(fwrite(buffer, 1, need, fout) < need) {
67 			if(error) *error = write_error;
68 			return false;
69 		}
70 		left -= need;
71 	}
72 	return true;
73 }
74 
75 /* compare 'size' bytes from file 'fin' to 'fout', filling in *error with 'read_error' or 'write_error' as necessary */
compare_data_(FILE * fin,FILE * fout,size_t size,const char ** error,const char * const read_error,const char * const write_error,const char * const compare_error)76 static FLAC__bool compare_data_(FILE *fin, FILE *fout, size_t size, const char **error, const char * const read_error, const char * const write_error, const char * const compare_error)
77 {
78 	FLAC__byte buffer_in[4096];
79 	FLAC__byte buffer_out[4096]; /* sizes need to be the same */
80 	size_t left;
81 	for(left = size; left > 0; ) {
82 		size_t need = min(sizeof(buffer_in), left);
83 		if(fread(buffer_in, 1, need, fin) < need) {
84 			if(error) *error = read_error;
85 			return false;
86 		}
87 		if(fread(buffer_out, 1, need, fout) < need) {
88 			if(error) *error = write_error;
89 			return false;
90 		}
91 		if(memcmp(buffer_in, buffer_out, need)) {
92 			if(error) *error = compare_error;
93 			return false;
94 		}
95 		left -= need;
96 	}
97 	return true;
98 }
99 
append_block_(foreign_metadata_t * fm,FLAC__off_t offset,FLAC__uint32 size,const char ** error)100 static FLAC__bool append_block_(foreign_metadata_t *fm, FLAC__off_t offset, FLAC__uint32 size, const char **error)
101 {
102 	foreign_block_t *fb;
103 	if(size >= ((1u << FLAC__STREAM_METADATA_LENGTH_LEN) - FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8)) {
104 		if(error) *error = "found foreign metadata chunk is too large (max is 16MiB per chunk)";
105 		return false;
106 	}
107 	fb = safe_realloc_nofree_muladd2_(fm->blocks, sizeof(foreign_block_t), /*times (*/fm->num_blocks, /*+*/1/*)*/);
108 	if(fb) {
109 		fb[fm->num_blocks].offset = offset;
110 		fb[fm->num_blocks].size = size;
111 		fm->num_blocks++;
112 		fm->blocks = fb;
113 		return true;
114 	}
115 	if(error) *error = "out of memory";
116 	return false;
117 }
118 
read_from_aiff_(foreign_metadata_t * fm,FILE * f,const char ** error)119 static FLAC__bool read_from_aiff_(foreign_metadata_t *fm, FILE *f, const char **error)
120 {
121 	FLAC__byte buffer[12];
122 	FLAC__off_t offset, eof_offset;
123 	if((offset = ftello(f)) < 0) {
124 		if(error) *error = "ftello() error (001)";
125 		return false;
126 	}
127 	if(fread(buffer, 1, 12, f) < 12 || memcmp(buffer, "FORM", 4) || (memcmp(buffer+8, "AIFF", 4) && memcmp(buffer+8, "AIFC", 4))) {
128 		if(error) *error = "unsupported FORM layout (002)";
129 		return false;
130 	}
131 	if(!append_block_(fm, offset, 12, error))
132 		return false;
133 	eof_offset = (FLAC__off_t)8 + (FLAC__off_t)unpack32be_(buffer+4);
134 	while(!feof(f)) {
135 		FLAC__uint32 size;
136 		if((offset = ftello(f)) < 0) {
137 			if(error) *error = "ftello() error (003)";
138 			return false;
139 		}
140 		if((size = fread(buffer, 1, 8, f)) < 8) {
141 			if(size == 0 && feof(f))
142 				break;
143 			if(error) *error = "invalid AIFF file (004)";
144 			return false;
145 		}
146 		size = unpack32be_(buffer+4);
147 		/* check if pad byte needed */
148 		if(size & 1)
149 			size++;
150 		if(!memcmp(buffer, "COMM", 4)) {
151 			if(fm->format_block) {
152 				if(error) *error = "invalid AIFF file: multiple \"COMM\" chunks (005)";
153 				return false;
154 			}
155 			if(fm->audio_block) {
156 				if(error) *error = "invalid AIFF file: \"SSND\" chunk before \"COMM\" chunk (006)";
157 				return false;
158 			}
159 			fm->format_block = fm->num_blocks;
160 		}
161 		else if(!memcmp(buffer, "SSND", 4)) {
162 			if(fm->audio_block) {
163 				if(error) *error = "invalid AIFF file: multiple \"SSND\" chunks (007)";
164 				return false;
165 			}
166 			if(!fm->format_block) {
167 				if(error) *error = "invalid AIFF file: \"SSND\" chunk before \"COMM\" chunk (008)";
168 				return false;
169 			}
170 			fm->audio_block = fm->num_blocks;
171 			/* read #offset bytes */
172 			if(fread(buffer+8, 1, 4, f) < 4) {
173 				if(error) *error = "invalid AIFF file (009)";
174 				return false;
175 			}
176 			fm->ssnd_offset_size = unpack32be_(buffer+8);
177 			if(fseeko(f, -4, SEEK_CUR) < 0) {
178 				if(error) *error = "invalid AIFF file: seek error (010)";
179 				return false;
180 			}
181 			/* WATCHOUT: For SSND we ignore the blockSize and are not saving any
182 			 * unaligned part at the end of the chunk.  In retrospect it is pretty
183 			 * pointless to save the unaligned data before the PCM but now it is
184 			 * done and cast in stone.
185 			 */
186 		}
187 		if(!append_block_(fm, offset, 8 + (memcmp(buffer, "SSND", 4)? size : 8 + fm->ssnd_offset_size), error))
188 			return false;
189 		/* skip to next chunk */
190 		if(fseeko(f, size, SEEK_CUR) < 0) {
191 			if(error) *error = "invalid AIFF file: seek error (011)";
192 			return false;
193 		}
194 	}
195 	if(eof_offset != ftello(f)) {
196 		if(error) *error = "invalid AIFF file: unexpected EOF (012)";
197 		return false;
198 	}
199 	if(!fm->format_block) {
200 		if(error) *error = "invalid AIFF file: missing \"COMM\" chunk (013)";
201 		return false;
202 	}
203 	if(!fm->audio_block) {
204 		if(error) *error = "invalid AIFF file: missing \"SSND\" chunk (014)";
205 		return false;
206 	}
207 	return true;
208 }
209 
read_from_wave_(foreign_metadata_t * fm,FILE * f,const char ** error)210 static FLAC__bool read_from_wave_(foreign_metadata_t *fm, FILE *f, const char **error)
211 {
212 	FLAC__byte buffer[12];
213 	FLAC__off_t offset, eof_offset = -1, ds64_data_size = -1;
214 	if((offset = ftello(f)) < 0) {
215 		if(error) *error = "ftello() error (001)";
216 		return false;
217 	}
218 	if(fread(buffer, 1, 12, f) < 12 || (memcmp(buffer, "RIFF", 4) && memcmp(buffer, "RF64", 4)) || memcmp(buffer+8, "WAVE", 4)) {
219 		if(error) *error = "unsupported RIFF layout (002)";
220 		return false;
221 	}
222 	if(!memcmp(buffer, "RF64", 4))
223 		fm->is_rf64 = true;
224 	if(fm->is_rf64 && sizeof(FLAC__off_t) < 8) {
225 		if(error) *error = "RF64 is not supported on this compile (r00)";
226 		return false;
227 	}
228 	if(!append_block_(fm, offset, 12, error))
229 		return false;
230 	if(!fm->is_rf64 || unpack32le_(buffer+4) != 0xffffffff) {
231 		eof_offset = (FLAC__off_t)8 + (FLAC__off_t)unpack32le_(buffer+4);
232 		if(eof_offset & 1) /* fix odd RIFF size */
233 			eof_offset++;
234 	}
235 	while(!feof(f)) {
236 		FLAC__off_t size;
237 		if((offset = ftello(f)) < 0) {
238 			if(error) *error = "ftello() error (003)";
239 			return false;
240 		}
241 		if((size = fread(buffer, 1, 8, f)) < 8) {
242 			if(size == 0 && feof(f))
243 				break;
244 			if(error) *error = "invalid WAVE file (004)";
245 			return false;
246 		}
247 		size = unpack32le_(buffer+4);
248 		/* check if pad byte needed */
249 		if(size & 1)
250 			size++;
251 		if(!memcmp(buffer, "fmt ", 4)) {
252 			if(fm->format_block) {
253 				if(error) *error = "invalid WAVE file: multiple \"fmt \" chunks (005)";
254 				return false;
255 			}
256 			if(fm->audio_block) {
257 				if(error) *error = "invalid WAVE file: \"data\" chunk before \"fmt \" chunk (006)";
258 				return false;
259 			}
260 			fm->format_block = fm->num_blocks;
261 		}
262 		else if(!memcmp(buffer, "data", 4)) {
263 			if(fm->audio_block) {
264 				if(error) *error = "invalid WAVE file: multiple \"data\" chunks (007)";
265 				return false;
266 			}
267 			if(!fm->format_block) {
268 				if(error) *error = "invalid WAVE file: \"data\" chunk before \"fmt \" chunk (008)";
269 				return false;
270 			}
271 			fm->audio_block = fm->num_blocks;
272 			if(fm->is_rf64 && fm->num_blocks < 2) {
273 				if(error) *error = "invalid RF64 file: \"data\" chunk before \"ds64\" chunk (r01)";
274 				return false;
275 			}
276 		}
277 		if(!append_block_(fm, offset, 8 + (memcmp(buffer, "data", 4)? size : 0), error))
278 			return false;
279 		/* parse ds64 chunk if necessary */
280 		if(fm->is_rf64 && fm->num_blocks == 2) {
281 			FLAC__byte buffer2[7*4];
282 			if(memcmp(buffer, "ds64", 4)) {
283 				if(error) *error = "invalid RF64 file: \"ds64\" chunk does not immediately follow \"WAVE\" marker (r02)";
284 				return false;
285 			}
286 			/* unpack the size again since we don't want the padding byte effect */
287 			size = unpack32le_(buffer+4);
288 			if(size < (FLAC__off_t)sizeof(buffer2)) {
289 				if(error) *error = "invalid RF64 file: \"ds64\" chunk size is < 28 (r03)";
290 				return false;
291 			}
292 			if(size > (FLAC__off_t)sizeof(buffer2)) {
293 				if(error) *error = "RF64 file has \"ds64\" chunk with extra size table, which is not currently supported (r04)";
294 				return false;
295 			}
296 			if(fread(buffer2, 1, sizeof(buffer2), f) < sizeof(buffer2)) {
297 				if(error) *error = "unexpected EOF reading \"ds64\" chunk data in RF64 file (r05)";
298 				return false;
299 			}
300 			ds64_data_size = (FLAC__off_t)unpack64le_(buffer2+8);
301 			if(ds64_data_size == (FLAC__off_t)(-1)) {
302 				if(error) *error = "RF64 file has \"ds64\" chunk with data size == -1 (r08)";
303 				return false;
304 			}
305 			/* check if pad byte needed */
306 			if(ds64_data_size & 1)
307 				ds64_data_size++;
308 			/* @@@ [2^63 limit] */
309 			if(ds64_data_size < 0) {
310 				if(error) *error = "RF64 file too large (r09)";
311 				return false;
312 			}
313 			if(unpack32le_(buffer2+24)) {
314 				if(error) *error = "RF64 file has \"ds64\" chunk with extra size table, which is not currently supported (r06)";
315 				return false;
316 			}
317 			eof_offset = (FLAC__off_t)8 + (FLAC__off_t)unpack64le_(buffer2);
318 			/* @@@ [2^63 limit] */
319 			if((FLAC__off_t)unpack64le_(buffer2) < 0 || eof_offset < 0) {
320 				if(error) *error = "RF64 file too large (r07)";
321 				return false;
322 			}
323 		}
324 		else { /* skip to next chunk */
325 			if(fm->is_rf64 && !memcmp(buffer, "data", 4) && unpack32le_(buffer+4) == 0xffffffff) {
326 				if(fseeko(f, ds64_data_size, SEEK_CUR) < 0) {
327 					if(error) *error = "invalid RF64 file: seek error (r10)";
328 					return false;
329 				}
330 			}
331 			else {
332 				if(fseeko(f, size, SEEK_CUR) < 0) {
333 					if(error) *error = "invalid WAVE file: seek error (009)";
334 					return false;
335 				}
336 			}
337 		}
338 	}
339 	if(fm->is_rf64 && eof_offset == (FLAC__off_t)(-1)) {
340 		if(error) *error = "invalid RF64 file: all RIFF sizes are -1 (r11)";
341 		return false;
342 	}
343 	if(eof_offset != ftello(f)) {
344 		if(error) *error = "invalid WAVE file: unexpected EOF (010)";
345 		return false;
346 	}
347 	if(!fm->format_block) {
348 		if(error) *error = "invalid WAVE file: missing \"fmt \" chunk (011)";
349 		return false;
350 	}
351 	if(!fm->audio_block) {
352 		if(error) *error = "invalid WAVE file: missing \"data\" chunk (012)";
353 		return false;
354 	}
355 	return true;
356 }
357 
read_from_wave64_(foreign_metadata_t * fm,FILE * f,const char ** error)358 static FLAC__bool read_from_wave64_(foreign_metadata_t *fm, FILE *f, const char **error)
359 {
360 	FLAC__byte buffer[40];
361 	FLAC__off_t offset, eof_offset = -1;
362 	if((offset = ftello(f)) < 0) {
363 		if(error) *error = "ftello() error (001)";
364 		return false;
365 	}
366 	if(
367 		fread(buffer, 1, 40, f) < 40 ||
368 		/* RIFF GUID 66666972-912E-11CF-A5D6-28DB04C10000 */
369 		memcmp(buffer, "\x72\x69\x66\x66\x2E\x91\xCF\x11\xA5\xD6\x28\xDB\x04\xC1\x00\x00", 16) ||
370 		/* WAVE GUID 65766177-ACF3-11D3-8CD1-00C04F8EDB8A */
371 		memcmp(buffer+24, "\x77\x61\x76\x65\xF3\xAC\xD3\x11\x8C\xD1\x00\xC0\x4F\x8E\xDB\x8A", 16)
372 	) {
373 		if(error) *error = "unsupported Wave64 layout (002)";
374 		return false;
375 	}
376 	if(sizeof(FLAC__off_t) < 8) {
377 		if(error) *error = "Wave64 is not supported on this compile (r00)";
378 		return false;
379 	}
380 	if(!append_block_(fm, offset, 40, error))
381 		return false;
382 	eof_offset = (FLAC__off_t)unpack64le_(buffer+16); /*@@@ [2^63 limit] */
383 	while(!feof(f)) {
384 		FLAC__uint64 size;
385 		if((offset = ftello(f)) < 0) {
386 			if(error) *error = "ftello() error (003)";
387 			return false;
388 		}
389 		if((size = fread(buffer, 1, 24, f)) < 24) {
390 			if(size == 0 && feof(f))
391 				break;
392 			if(error) *error = "invalid Wave64 file (004)";
393 			return false;
394 		}
395 		size = unpack64le_(buffer+16);
396 		/* check if pad bytes needed */
397 		if(size & 7)
398 			size = (size+7) & (~((FLAC__uint64)7));
399 		/* fmt GUID 20746D66-ACF3-11D3-8CD1-00C04F8EDB8A */
400 		if(!memcmp(buffer, "\x66\x6D\x74\x20\xF3\xAC\xD3\x11\x8C\xD1\x00\xC0\x4F\x8E\xDB\x8A", 16)) {
401 			if(fm->format_block) {
402 				if(error) *error = "invalid Wave64 file: multiple \"fmt \" chunks (005)";
403 				return false;
404 			}
405 			if(fm->audio_block) {
406 				if(error) *error = "invalid Wave64 file: \"data\" chunk before \"fmt \" chunk (006)";
407 				return false;
408 			}
409 			fm->format_block = fm->num_blocks;
410 		}
411 		/* data GUID 61746164-ACF3-11D3-8CD1-00C04F8EDB8A */
412 		else if(!memcmp(buffer, "\x64\x61\x74\x61\xF3\xAC\xD3\x11\x8C\xD1\x00\xC0\x4F\x8E\xDB\x8A", 16)) {
413 			if(fm->audio_block) {
414 				if(error) *error = "invalid Wave64 file: multiple \"data\" chunks (007)";
415 				return false;
416 			}
417 			if(!fm->format_block) {
418 				if(error) *error = "invalid Wave64 file: \"data\" chunk before \"fmt \" chunk (008)";
419 				return false;
420 			}
421 			fm->audio_block = fm->num_blocks;
422 		}
423 		if(!append_block_(fm, offset, memcmp(buffer, "\x64\x61\x74\x61\xF3\xAC\xD3\x11\x8C\xD1\x00\xC0\x4F\x8E\xDB\x8A", 16)? (FLAC__uint32)size : 16+8, error))
424 			return false;
425 		/* skip to next chunk */
426 		if(fseeko(f, size-24, SEEK_CUR) < 0) {
427 			if(error) *error = "invalid Wave64 file: seek error (009)";
428 			return false;
429 		}
430 	}
431 	if(eof_offset != ftello(f)) {
432 		if(error) *error = "invalid Wave64 file: unexpected EOF (010)";
433 		return false;
434 	}
435 	if(!fm->format_block) {
436 		if(error) *error = "invalid Wave64 file: missing \"fmt \" chunk (011)";
437 		return false;
438 	}
439 	if(!fm->audio_block) {
440 		if(error) *error = "invalid Wave64 file: missing \"data\" chunk (012)";
441 		return false;
442 	}
443 	return true;
444 }
445 
write_to_flac_(foreign_metadata_t * fm,FILE * fin,FILE * fout,FLAC__Metadata_SimpleIterator * it,const char ** error)446 static FLAC__bool write_to_flac_(foreign_metadata_t *fm, FILE *fin, FILE *fout, FLAC__Metadata_SimpleIterator *it, const char **error)
447 {
448 	FLAC__byte buffer[4];
449 	const uint32_t ID_LEN = FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8;
450 	size_t block_num = 0;
451 	FLAC__ASSERT(sizeof(buffer) >= ID_LEN);
452 	while(block_num < fm->num_blocks) {
453 		/* find next matching padding block */
454 		do {
455 			/* even on the first chunk's loop there will be a skippable STREAMINFO block, on subsequent loops we are first moving past the PADDING we just used */
456 			if(!FLAC__metadata_simple_iterator_next(it)) {
457 				if(error) *error = "no matching PADDING block found (004)";
458 				return false;
459 			}
460 		} while(FLAC__metadata_simple_iterator_get_block_type(it) != FLAC__METADATA_TYPE_PADDING);
461 		if(FLAC__metadata_simple_iterator_get_block_length(it) != ID_LEN+fm->blocks[block_num].size) {
462 			if(error) *error = "PADDING block with wrong size found (005)";
463 			return false;
464 		}
465 		/* transfer chunk into APPLICATION block */
466 		/* first set up the file pointers */
467 		if(fseeko(fin, fm->blocks[block_num].offset, SEEK_SET) < 0) {
468 			if(error) *error = "seek failed in WAVE/AIFF file (006)";
469 			return false;
470 		}
471 		if(fseeko(fout, FLAC__metadata_simple_iterator_get_block_offset(it), SEEK_SET) < 0) {
472 			if(error) *error = "seek failed in FLAC file (007)";
473 			return false;
474 		}
475 		/* update the type */
476 		buffer[0] = FLAC__METADATA_TYPE_APPLICATION;
477 		if(FLAC__metadata_simple_iterator_is_last(it))
478 			buffer[0] |= 0x80; /*MAGIC number*/
479 		if(fwrite(buffer, 1, 1, fout) < 1) {
480 			if(error) *error = "write failed in FLAC file (008)";
481 			return false;
482 		}
483 		/* length stays the same so skip over it */
484 		if(fseeko(fout, FLAC__STREAM_METADATA_LENGTH_LEN/8, SEEK_CUR) < 0) {
485 			if(error) *error = "seek failed in FLAC file (009)";
486 			return false;
487 		}
488 		/* write the APPLICATION ID */
489 		memcpy(buffer, FLAC__FOREIGN_METADATA_APPLICATION_ID[fm->type], ID_LEN);
490 		if(fwrite(buffer, 1, ID_LEN, fout) < ID_LEN) {
491 			if(error) *error = "write failed in FLAC file (010)";
492 			return false;
493 		}
494 		/* transfer the foreign metadata */
495 		if(!copy_data_(fin, fout, fm->blocks[block_num].size, error, "read failed in WAVE/AIFF file (011)", "write failed in FLAC file (012)"))
496 			return false;
497 		block_num++;
498 	}
499 	return true;
500 }
501 
read_from_flac_(foreign_metadata_t * fm,FILE * f,FLAC__Metadata_SimpleIterator * it,const char ** error)502 static FLAC__bool read_from_flac_(foreign_metadata_t *fm, FILE *f, FLAC__Metadata_SimpleIterator *it, const char **error)
503 {
504 	FLAC__byte id[4], buffer[32];
505 	FLAC__off_t offset;
506 	FLAC__uint32 length;
507 	FLAC__bool first_block = true, type_found = false, ds64_found = false;
508 
509 	FLAC__ASSERT(FLAC__STREAM_METADATA_APPLICATION_ID_LEN == sizeof(id)*8);
510 
511 	while(FLAC__metadata_simple_iterator_next(it)) {
512 		if(FLAC__metadata_simple_iterator_get_block_type(it) != FLAC__METADATA_TYPE_APPLICATION)
513 			continue;
514 		if(!FLAC__metadata_simple_iterator_get_application_id(it, id)) {
515 			if(error) *error = "FLAC__metadata_simple_iterator_get_application_id() error (002)";
516 			return false;
517 		}
518 		if(first_block) {
519 			uint32_t i;
520 			for(i = 0; i < FLAC__FOREIGN_METADATA_NUMBER_OF_RECOGNIZED_APPLICATION_IDS; i++)
521 				if(memcmp(id, FLAC__FOREIGN_METADATA_APPLICATION_ID[i], sizeof(id)) == 0) {
522 					fm->type = i;
523 					first_block = false;
524 				}
525 			if(first_block) /* means no first foreign metadata block was found yet */
526 				continue;
527 		}
528 		else if(memcmp(id, FLAC__FOREIGN_METADATA_APPLICATION_ID[fm->type], sizeof(id)))
529 			continue;
530 		offset = FLAC__metadata_simple_iterator_get_block_offset(it);
531 		length = FLAC__metadata_simple_iterator_get_block_length(it);
532 		/* skip over header and app ID */
533 		offset += (FLAC__STREAM_METADATA_IS_LAST_LEN + FLAC__STREAM_METADATA_TYPE_LEN + FLAC__STREAM_METADATA_LENGTH_LEN) / 8;
534 		offset += sizeof(id);
535 		/* look for format or audio blocks */
536 		if(fseeko(f, offset, SEEK_SET) < 0) {
537 			if(error) *error = "seek error (003)";
538 			return false;
539 		}
540 		if(fread(buffer, 1, 4, f) != 4) {
541 			if(error) *error = "read error (004)";
542 			return false;
543 		}
544 		if(fm->num_blocks == 0) { /* first block? */
545 			/* Initialize bools */
546 			fm->is_wavefmtex = 0;
547 			fm->is_aifc = 0;
548 			fm->is_sowt = 0;
549 			fm->is_rf64 = 0 == memcmp(buffer, "RF64", 4);
550 
551 			if(fm->type == FOREIGN_BLOCK_TYPE__RIFF && (0 == memcmp(buffer, "RIFF", 4) || fm->is_rf64))
552 				type_found = true;
553 			else if(fm->type == FOREIGN_BLOCK_TYPE__WAVE64 && 0 == memcmp(buffer, "riff", 4)) /* use first 4 bytes instead of whole GUID */
554 				type_found = true;
555 			else if(fm->type == FOREIGN_BLOCK_TYPE__AIFF && 0 == memcmp(buffer, "FORM", 4)) {
556 				type_found = true;
557 				if(fread(buffer+4, 1, 8, f) != 8) {
558 					if(error) *error = "read error (020)";
559 					return false;
560 				}
561 				fm->is_aifc = 0 == memcmp(buffer+8, "AIFC", 4);
562 			}
563 			else {
564 				if(error) *error = "unsupported foreign metadata found, may need newer FLAC decoder (005)";
565 				return false;
566 			}
567 		}
568 		else if(!type_found) {
569 			FLAC__ASSERT(0);
570 			/* double protection: */
571 			if(error) *error = "unsupported foreign metadata found, may need newer FLAC decoder (006)";
572 			return false;
573 		}
574 		else if(fm->type == FOREIGN_BLOCK_TYPE__RIFF) {
575 			if(!memcmp(buffer, "fmt ", 4)) {
576 				if(fm->format_block) {
577 					if(error) *error = "invalid WAVE metadata: multiple \"fmt \" chunks (007)";
578 					return false;
579 				}
580 				if(fm->audio_block) {
581 					if(error) *error = "invalid WAVE metadata: \"data\" chunk before \"fmt \" chunk (008)";
582 					return false;
583 				}
584 				fm->format_block = fm->num_blocks;
585 				if(fread(buffer+4, 1, 8, f) != 8) {
586 					if(error) *error = "read error (020)";
587 					return false;
588 				}
589 				fm->is_wavefmtex = 0 == memcmp(buffer+8, "\xfe\xff", 2);
590 			}
591 			else if(!memcmp(buffer, "data", 4)) {
592 				if(fm->audio_block) {
593 					if(error) *error = "invalid WAVE metadata: multiple \"data\" chunks (009)";
594 					return false;
595 				}
596 				if(!fm->format_block) {
597 					if(error) *error = "invalid WAVE metadata: \"data\" chunk before \"fmt \" chunk (010)";
598 					return false;
599 				}
600 				fm->audio_block = fm->num_blocks;
601 			}
602 			else if(fm->is_rf64 && fm->num_blocks == 1) {
603 				if(memcmp(buffer, "ds64", 4)) {
604 					if(error) *error = "invalid RF64 metadata: second chunk is not \"ds64\" (011)";
605 					return false;
606 				}
607 				ds64_found = true;
608 			}
609 		}
610 		else if(fm->type == FOREIGN_BLOCK_TYPE__WAVE64) {
611 			if(!memcmp(buffer, "fmt ", 4)) { /* use first 4 bytes instead of whole GUID */
612 				if(fm->format_block) {
613 					if(error) *error = "invalid Wave64 metadata: multiple \"fmt \" chunks (012)";
614 					return false;
615 				}
616 				if(fm->audio_block) {
617 					if(error) *error = "invalid Wave64 metadata: \"data\" chunk before \"fmt \" chunk (013)";
618 					return false;
619 				}
620 				fm->format_block = fm->num_blocks;
621 			}
622 			else if(!memcmp(buffer, "data", 4)) { /* use first 4 bytes instead of whole GUID */
623 				if(fm->audio_block) {
624 					if(error) *error = "invalid Wave64 metadata: multiple \"data\" chunks (014)";
625 					return false;
626 				}
627 				if(!fm->format_block) {
628 					if(error) *error = "invalid Wave64 metadata: \"data\" chunk before \"fmt \" chunk (015)";
629 					return false;
630 				}
631 				fm->audio_block = fm->num_blocks;
632 			}
633 		}
634 		else if(fm->type == FOREIGN_BLOCK_TYPE__AIFF) {
635 			if(!memcmp(buffer, "COMM", 4)) {
636 				if(fm->format_block) {
637 					if(error) *error = "invalid AIFF metadata: multiple \"COMM\" chunks (016)";
638 					return false;
639 				}
640 				if(fm->audio_block) {
641 					if(error) *error = "invalid AIFF metadata: \"SSND\" chunk before \"COMM\" chunk (017)";
642 					return false;
643 				}
644 				fm->format_block = fm->num_blocks;
645 				if(fm->is_aifc) {
646 					if(fread(buffer+4, 1, 26, f) != 26) {
647 						if(error) *error = "read error (020)";
648 						return false;
649 					}
650 					fm->is_sowt = 0 == memcmp(buffer+26, "sowt", 2);
651 					fm->aifc_comm_length = length;
652 				}
653 			}
654 			else if(!memcmp(buffer, "SSND", 4)) {
655 				if(fm->audio_block) {
656 					if(error) *error = "invalid AIFF metadata: multiple \"SSND\" chunks (018)";
657 					return false;
658 				}
659 				if(!fm->format_block) {
660 					if(error) *error = "invalid AIFF metadata: \"SSND\" chunk before \"COMM\" chunk (019)";
661 					return false;
662 				}
663 				fm->audio_block = fm->num_blocks;
664 				/* read SSND offset size */
665 				if(fread(buffer+4, 1, 8, f) != 8) {
666 					if(error) *error = "read error (020)";
667 					return false;
668 				}
669 				fm->ssnd_offset_size = unpack32be_(buffer+8);
670 			}
671 		}
672 		else {
673 			FLAC__ASSERT(0);
674 			/* double protection: */
675 			if(error) *error = "unsupported foreign metadata found, may need newer FLAC decoder (021)";
676 			return false;
677 		}
678 		if(!append_block_(fm, offset, FLAC__metadata_simple_iterator_get_block_length(it)-sizeof(id), error))
679 			return false;
680 	}
681 	if(fm->is_rf64 && !ds64_found) {
682 		if(error) *error = "invalid RF64 file: second chunk is not \"ds64\" (023)";
683 		return false;
684 	}
685 	if(!fm->format_block) {
686 		if(error)
687 			*error =
688 				fm->type==FOREIGN_BLOCK_TYPE__RIFF? "invalid WAVE file: missing \"fmt \" chunk (024)" :
689 				fm->type==FOREIGN_BLOCK_TYPE__WAVE64? "invalid Wave64 file: missing \"fmt \" chunk (025)" :
690 				"invalid AIFF file: missing \"COMM\" chunk (026)";
691 		return false;
692 	}
693 	if(!fm->audio_block) {
694 		if(error)
695 			*error =
696 				fm->type==FOREIGN_BLOCK_TYPE__RIFF? "invalid WAVE file: missing \"data\" chunk (027)" :
697 				fm->type==FOREIGN_BLOCK_TYPE__WAVE64? "invalid Wave64 file: missing \"data\" chunk (028)" :
698 				"invalid AIFF file: missing \"SSND\" chunk (029)";
699 		return false;
700 	}
701 	return true;
702 }
703 
write_to_iff_(foreign_metadata_t * fm,FILE * fin,FILE * fout,FLAC__off_t offset1,FLAC__off_t offset2,FLAC__off_t offset3,const char ** error)704 static FLAC__bool write_to_iff_(foreign_metadata_t *fm, FILE *fin, FILE *fout, FLAC__off_t offset1, FLAC__off_t offset2, FLAC__off_t offset3, const char **error)
705 {
706 	size_t i;
707 	if(fseeko(fout, offset1, SEEK_SET) < 0) {
708 		if(error) *error = "seek failed in WAVE/AIFF file";
709 		return false;
710 	}
711 
712 	/* don't write first (RIFF/RF64/FORM) chunk, or ds64 chunk in the case of RF64 */
713 	for(i = fm->is_rf64?2:1; i < fm->format_block; i++) {
714 		if(fseeko(fin, fm->blocks[i].offset, SEEK_SET) < 0) {
715 			if(error) *error = "seek failed in FLAC file";
716 			return false;
717 		}
718 		if(!copy_data_(fin, fout, fm->blocks[i].size, error, "read failed in FLAC file", "write failed in WAVE/AIFF file"))
719 			return false;
720 	}
721 
722 	if(fm->is_aifc) {
723 		/* Need to restore compression type name */
724 		if(fseeko(fout, 30, SEEK_CUR) < 0) {
725 			if(error) *error = "seek failed in AIFF-C file";
726 			return false;
727 		}
728 		if(fseeko(fin, fm->blocks[i].offset+30, SEEK_SET) < 0) {
729 			if(error) *error = "seek failed in FLAC file";
730 			return false;
731 		}
732 		if(!copy_data_(fin, fout, fm->aifc_comm_length-34, error, "read failed in FLAC file", "write failed in WAVE/AIFF file"))
733 			return false;
734 		/* Now seek back */
735 		if(fseeko(fout, ((FLAC__int32)(fm->aifc_comm_length) * -1) + 4, SEEK_CUR) < 0) {
736 			if(error) *error = "seek failed in AIFF-C file";
737 			return false;
738 		}
739 	}
740 	if(fseeko(fout, offset2, SEEK_SET) < 0) {
741 		if(error) *error = "seek failed in WAVE/AIFF file (006)";
742 		return false;
743 	}
744 	for(i = fm->format_block+1; i < fm->audio_block; i++) {
745 		if(fseeko(fin, fm->blocks[i].offset, SEEK_SET) < 0) {
746 			if(error) *error = "seek failed in FLAC file";
747 			return false;
748 		}
749 		if(!copy_data_(fin, fout, fm->blocks[i].size, error, "read failed in FLAC file", "write failed in WAVE/AIFF file"))
750 			return false;
751 	}
752 	if(fseeko(fout, offset3, SEEK_SET) < 0) {
753 		if(error) *error = "seek failed in WAVE/AIFF file";
754 		return false;
755 	}
756 	for(i = fm->audio_block+1; i < fm->num_blocks; i++) {
757 		if(fseeko(fin, fm->blocks[i].offset, SEEK_SET) < 0) {
758 			if(error) *error = "seek failed in FLAC file";
759 			return false;
760 		}
761 		if(!copy_data_(fin, fout, fm->blocks[i].size, error, "read failed in FLAC file", "write failed in WAVE/AIFF file"))
762 			return false;
763 	}
764 	return true;
765 }
766 
compare_with_iff_(foreign_metadata_t * fm,FILE * fin,FILE * fout,FLAC__off_t offset3,const char ** error)767 static FLAC__bool compare_with_iff_(foreign_metadata_t *fm, FILE *fin, FILE *fout, FLAC__off_t offset3, const char **error)
768 {
769 	size_t i;
770 
771 	/* Compare blocks before audio data */
772 	for(i = 0; i <= (fm->audio_block); i++) {
773 		if(fseeko(fin, fm->blocks[i].offset, SEEK_SET) < 0) {
774 			if(error) *error = "seek failed in FLAC file";
775 			return false;
776 		}
777 		if(!compare_data_(fin, fout, fm->blocks[i].size, error, "read failed in FLAC file", "read failed in WAVE/AIFF file",
778 		      i==0?"stored main chunk length differs from written length":(
779 		      i==fm->format_block?"stored foreign format block differs from written block. Perhaps the file is being restored to a different format than that of the original file":(
780 		      i==fm->audio_block?"stored audio length differs from written length. Perhaps the file changed in length after being originally encoded":"restore of foreign metadata failed"))))
781 			return false;
782 	}
783 
784 	/* Seek beyond audio */
785 	if(fseeko(fout, offset3, SEEK_SET) < 0) {
786 		if(error) *error = "seek failed in WAVE/AIFF file";
787 		return false;
788 	}
789 	for(; i < fm->num_blocks; i++) {
790 		if(fseeko(fin, fm->blocks[i].offset, SEEK_SET) < 0) {
791 			if(error) *error = "seek failed in FLAC file";
792 			return false;
793 		}
794 		if(!compare_data_(fin, fout, fm->blocks[i].size, error, "read failed in FLAC file", "read failed in WAVE/AIFF file", "restore of foreign metadata failed"))
795 			return false;
796 	}
797 	return true;
798 }
799 
flac__foreign_metadata_new(foreign_block_type_t type)800 foreign_metadata_t *flac__foreign_metadata_new(foreign_block_type_t type)
801 {
802 	/* calloc() to zero all the member variables */
803 	foreign_metadata_t *x = calloc(sizeof(foreign_metadata_t), 1);
804 	if(x) {
805 		x->type = type;
806 		x->is_rf64 = false;
807 	}
808 	return x;
809 }
810 
flac__foreign_metadata_delete(foreign_metadata_t * fm)811 void flac__foreign_metadata_delete(foreign_metadata_t *fm)
812 {
813 	if(fm) {
814 		if(fm->blocks)
815 			free(fm->blocks);
816 		free(fm);
817 	}
818 }
819 
flac__foreign_metadata_read_from_aiff(foreign_metadata_t * fm,const char * filename,const char ** error)820 FLAC__bool flac__foreign_metadata_read_from_aiff(foreign_metadata_t *fm, const char *filename, const char **error)
821 {
822 	FLAC__bool ok;
823 	FILE *f = flac_fopen(filename, "rb");
824 	if(!f) {
825 		if(error) *error = "can't open AIFF file for reading (000)";
826 		return false;
827 	}
828 	ok = read_from_aiff_(fm, f, error);
829 	fclose(f);
830 	return ok;
831 }
832 
flac__foreign_metadata_read_from_wave(foreign_metadata_t * fm,const char * filename,const char ** error)833 FLAC__bool flac__foreign_metadata_read_from_wave(foreign_metadata_t *fm, const char *filename, const char **error)
834 {
835 	FLAC__bool ok;
836 	FILE *f = flac_fopen(filename, "rb");
837 	if(!f) {
838 		if(error) *error = "can't open WAVE file for reading (000)";
839 		return false;
840 	}
841 	ok = read_from_wave_(fm, f, error);
842 	fclose(f);
843 	return ok;
844 }
845 
flac__foreign_metadata_read_from_wave64(foreign_metadata_t * fm,const char * filename,const char ** error)846 FLAC__bool flac__foreign_metadata_read_from_wave64(foreign_metadata_t *fm, const char *filename, const char **error)
847 {
848 	FLAC__bool ok;
849 	FILE *f = flac_fopen(filename, "rb");
850 	if(!f) {
851 		if(error) *error = "can't open Wave64 file for reading (000)";
852 		return false;
853 	}
854 	ok = read_from_wave64_(fm, f, error);
855 	fclose(f);
856 	return ok;
857 }
858 
flac__foreign_metadata_write_to_flac(foreign_metadata_t * fm,const char * infilename,const char * outfilename,const char ** error)859 FLAC__bool flac__foreign_metadata_write_to_flac(foreign_metadata_t *fm, const char *infilename, const char *outfilename, const char **error)
860 {
861 	FLAC__bool ok;
862 	FILE *fin, *fout;
863 	FLAC__Metadata_SimpleIterator *it = FLAC__metadata_simple_iterator_new();
864 	if(!it) {
865 		if(error) *error = "out of memory (000)";
866 		return false;
867 	}
868 	if(!FLAC__metadata_simple_iterator_init(it, outfilename, /*read_only=*/true, /*preserve_file_stats=*/false)) {
869 		if(error) *error = "can't initialize iterator (001)";
870 		FLAC__metadata_simple_iterator_delete(it);
871 		return false;
872 	}
873 	if(0 == (fin = flac_fopen(infilename, "rb"))) {
874 		if(error) *error = "can't open WAVE/AIFF file for reading (002)";
875 		FLAC__metadata_simple_iterator_delete(it);
876 		return false;
877 	}
878 	if(0 == (fout = flac_fopen(outfilename, "r+b"))) {
879 		if(error) *error = "can't open FLAC file for updating (003)";
880 		FLAC__metadata_simple_iterator_delete(it);
881 		fclose(fin);
882 		return false;
883 	}
884 	ok = write_to_flac_(fm, fin, fout, it, error);
885 	FLAC__metadata_simple_iterator_delete(it);
886 	fclose(fin);
887 	fclose(fout);
888 	return ok;
889 }
890 
flac__foreign_metadata_read_from_flac(foreign_metadata_t * fm,const char * filename,const char ** error)891 FLAC__bool flac__foreign_metadata_read_from_flac(foreign_metadata_t *fm, const char *filename, const char **error)
892 {
893 	FLAC__bool ok;
894 	FILE *f;
895 	FLAC__Metadata_SimpleIterator *it = FLAC__metadata_simple_iterator_new();
896 	if(!it) {
897 		if(error) *error = "out of memory (000)";
898 		return false;
899 	}
900 	if(!FLAC__metadata_simple_iterator_init(it, filename, /*read_only=*/true, /*preserve_file_stats=*/false)) {
901 		if(error) *error = "can't initialize iterator (001)";
902 		FLAC__metadata_simple_iterator_delete(it);
903 		return false;
904 	}
905 	if(0 == (f = flac_fopen(filename, "rb"))) {
906 		if(error) *error = "can't open FLAC file for reading (002)";
907 		FLAC__metadata_simple_iterator_delete(it);
908 		return false;
909 	}
910 	ok = read_from_flac_(fm, f, it, error);
911 	FLAC__metadata_simple_iterator_delete(it);
912 	fclose(f);
913 	return ok;
914 }
915 
flac__foreign_metadata_write_to_iff(foreign_metadata_t * fm,const char * infilename,const char * outfilename,FLAC__off_t offset1,FLAC__off_t offset2,FLAC__off_t offset3,const char ** error)916 FLAC__bool flac__foreign_metadata_write_to_iff(foreign_metadata_t *fm, const char *infilename, const char *outfilename, FLAC__off_t offset1, FLAC__off_t offset2, FLAC__off_t offset3, const char **error)
917 {
918 	FLAC__bool ok;
919 	FILE *fin, *fout;
920 	if(0 == (fin = flac_fopen(infilename, "rb"))) {
921 		if(error) *error = "can't open FLAC file for reading (000)";
922 		return false;
923 	}
924 	if(0 == (fout = flac_fopen(outfilename, "r+b"))) {
925 		if(error) *error = "can't open WAVE/AIFF file for updating (001)";
926 		fclose(fin);
927 		return false;
928 	}
929 	ok = write_to_iff_(fm, fin, fout, offset1, offset2, offset3, error);
930 	fclose(fin);
931 	fclose(fout);
932 	return ok;
933 }
934 
flac__foreign_metadata_compare_with_iff(foreign_metadata_t * fm,const char * infilename,const char * outfilename,FLAC__off_t offset3,const char ** error)935 FLAC__bool flac__foreign_metadata_compare_with_iff(foreign_metadata_t *fm, const char *infilename, const char *outfilename, FLAC__off_t offset3, const char **error)
936 {
937 	FLAC__bool ok;
938 	FILE *fin, *fout;
939 	if(0 == (fin = flac_fopen(infilename, "rb"))) {
940 		if(error) *error = "can't open FLAC file for reading";
941 		return false;
942 	}
943 	if(0 == (fout = flac_fopen(outfilename, "rb"))) {
944 		if(error) *error = "can't open WAVE/AIFF file for comparing";
945 		fclose(fin);
946 		return false;
947 	}
948 	ok = compare_with_iff_(fm, fin, fout, offset3, error);
949 	fclose(fin);
950 	fclose(fout);
951 	return ok;
952 }
953