1 /* flac - Command-line FLAC encoder/decoder
2  * Copyright (C) 2000,2001,2002,2003,2004,2005,2006,2007  Josh Coalson
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
17  */
18 
19 #if HAVE_CONFIG_H
20 #  include <config.h>
21 #endif
22 
23 #if defined _MSC_VER || defined __MINGW32__
24 #include <sys/types.h> /* for off_t */
25 #if _MSC_VER <= 1600 /* @@@ [2G limit] */
26 #define fseeko fseek
27 #define ftello ftell
28 #endif
29 #endif
30 #include <stdio.h> /* for FILE etc. */
31 #include <stdlib.h> /* for calloc() etc. */
32 #include <string.h> /* for memcmp() etc. */
33 #include "FLAC/assert.h"
34 #include "FLAC/metadata.h"
35 #include "share/alloc.h"
36 #include "foreign_metadata.h"
37 
38 #ifdef min
39 #undef min
40 #endif
41 #define min(x,y) ((x)<(y)?(x):(y))
42 
43 
44 static const char *FLAC__FOREIGN_METADATA_APPLICATION_ID[2] = { "aiff" , "riff" };
45 
unpack32be_(const FLAC__byte * b)46 static FLAC__uint32 unpack32be_(const FLAC__byte *b)
47 {
48 	return ((FLAC__uint32)b[0]<<24) + ((FLAC__uint32)b[1]<<16) + ((FLAC__uint32)b[2]<<8) + (FLAC__uint32)b[3];
49 }
50 
unpack32le_(const FLAC__byte * b)51 static FLAC__uint32 unpack32le_(const FLAC__byte *b)
52 {
53 	return (FLAC__uint32)b[0] + ((FLAC__uint32)b[1]<<8) + ((FLAC__uint32)b[2]<<16) + ((FLAC__uint32)b[3]<<24);
54 }
55 
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 	static 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 
append_block_(foreign_metadata_t * fm,off_t offset,FLAC__uint32 size,const char ** error)75 static FLAC__bool append_block_(foreign_metadata_t *fm, off_t offset, FLAC__uint32 size, const char **error)
76 {
77 	foreign_block_t *fb = safe_realloc_muladd2_(fm->blocks, sizeof(foreign_block_t), /*times (*/fm->num_blocks, /*+*/1/*)*/);
78 	if(fb) {
79 		fb[fm->num_blocks].offset = offset;
80 		fb[fm->num_blocks].size = size;
81 		fm->num_blocks++;
82 		fm->blocks = fb;
83 		return true;
84 	}
85 	if(error) *error = "out of memory";
86 	return false;
87 }
88 
read_from_aiff_(foreign_metadata_t * fm,FILE * f,const char ** error)89 static FLAC__bool read_from_aiff_(foreign_metadata_t *fm, FILE *f, const char **error)
90 {
91 	FLAC__byte buffer[12];
92 	off_t offset, eof_offset;
93 	if((offset = ftello(f)) < 0) {
94 		if(error) *error = "ftello() error (001)";
95 		return false;
96 	}
97 	if(fread(buffer, 1, 12, f) < 12 || memcmp(buffer, "FORM", 4) || (memcmp(buffer+8, "AIFF", 4) && memcmp(buffer+8, "AIFC", 4))) {
98 		if(error) *error = "unsupported FORM layout (002)";
99 		return false;
100 	}
101 	if(!append_block_(fm, offset, 12, error))
102 		return false;
103 	eof_offset = 8 + unpack32be_(buffer+4);
104 	while(!feof(f)) {
105 		FLAC__uint32 size;
106 		if((offset = ftello(f)) < 0) {
107 			if(error) *error = "ftello() error (003)";
108 			return false;
109 		}
110 		if((size = fread(buffer, 1, 8, f)) < 8) {
111 			if(size == 0 && feof(f))
112 				break;
113 			if(error) *error = "invalid AIFF file (004)";
114 			return false;
115 		}
116 		size = unpack32be_(buffer+4);
117 		/* check if pad byte needed */
118 		if(size & 1)
119 			size++;
120 		if(!memcmp(buffer, "COMM", 4)) {
121 			if(fm->format_block) {
122 				if(error) *error = "invalid AIFF file: multiple \"COMM\" chunks (005)";
123 				return false;
124 			}
125 			if(fm->audio_block) {
126 				if(error) *error = "invalid AIFF file: \"SSND\" chunk before \"COMM\" chunk (006)";
127 				return false;
128 			}
129 			fm->format_block = fm->num_blocks;
130 		}
131 		else if(!memcmp(buffer, "SSND", 4)) {
132 			if(fm->audio_block) {
133 				if(error) *error = "invalid AIFF file: multiple \"SSND\" chunks (007)";
134 				return false;
135 			}
136 			if(!fm->format_block) {
137 				if(error) *error = "invalid AIFF file: \"SSND\" chunk before \"COMM\" chunk (008)";
138 				return false;
139 			}
140 			fm->audio_block = fm->num_blocks;
141 			/* read #offset bytes */
142 			if(fread(buffer+8, 1, 4, f) < 4) {
143 				if(error) *error = "invalid AIFF file (009)";
144 				return false;
145 			}
146 			fm->ssnd_offset_size = unpack32be_(buffer+8);
147 			if(fseeko(f, -4, SEEK_CUR) < 0) {
148 				if(error) *error = "invalid AIFF file: seek error (010)";
149 				return false;
150 			}
151 		}
152 		if(!append_block_(fm, offset, 8 + (memcmp(buffer, "SSND", 4)? size : 8 + fm->ssnd_offset_size), error))
153 			return false;
154 		if(fseeko(f, size, SEEK_CUR) < 0) {
155 			if(error) *error = "invalid AIFF file: seek error (011)";
156 			return false;
157 		}
158 	}
159 	if(eof_offset != ftello(f)) {
160 		if(error) *error = "invalid AIFF file: unexpected EOF (012)";
161 		return false;
162 	}
163 	if(!fm->format_block) {
164 		if(error) *error = "invalid AIFF file: missing \"COMM\" chunk (013)";
165 		return false;
166 	}
167 	if(!fm->audio_block) {
168 		if(error) *error = "invalid AIFF file: missing \"SSND\" chunk (014)";
169 		return false;
170 	}
171 	return true;
172 }
173 
read_from_wave_(foreign_metadata_t * fm,FILE * f,const char ** error)174 static FLAC__bool read_from_wave_(foreign_metadata_t *fm, FILE *f, const char **error)
175 {
176 	FLAC__byte buffer[12];
177 	off_t offset, eof_offset;
178 	if((offset = ftello(f)) < 0) {
179 		if(error) *error = "ftello() error (001)";
180 		return false;
181 	}
182 	if(fread(buffer, 1, 12, f) < 12 || memcmp(buffer, "RIFF", 4) || memcmp(buffer+8, "WAVE", 4)) {
183 		if(error) *error = "unsupported RIFF layout (002)";
184 		return false;
185 	}
186 	if(!append_block_(fm, offset, 12, error))
187 		return false;
188 	eof_offset = 8 + unpack32le_(buffer+4);
189 	while(!feof(f)) {
190 		FLAC__uint32 size;
191 		if((offset = ftello(f)) < 0) {
192 			if(error) *error = "ftello() error (003)";
193 			return false;
194 		}
195 		if((size = fread(buffer, 1, 8, f)) < 8) {
196 			if(size == 0 && feof(f))
197 				break;
198 			if(error) *error = "invalid WAVE file (004)";
199 			return false;
200 		}
201 		size = unpack32le_(buffer+4);
202 		/* check if pad byte needed */
203 		if(size & 1)
204 			size++;
205 		if(!memcmp(buffer, "fmt ", 4)) {
206 			if(fm->format_block) {
207 				if(error) *error = "invalid WAVE file: multiple \"fmt \" chunks (005)";
208 				return false;
209 			}
210 			if(fm->audio_block) {
211 				if(error) *error = "invalid WAVE file: \"data\" chunk before \"fmt \" chunk (006)";
212 				return false;
213 			}
214 			fm->format_block = fm->num_blocks;
215 		}
216 		else if(!memcmp(buffer, "data", 4)) {
217 			if(fm->audio_block) {
218 				if(error) *error = "invalid WAVE file: multiple \"data\" chunks (007)";
219 				return false;
220 			}
221 			if(!fm->format_block) {
222 				if(error) *error = "invalid WAVE file: \"data\" chunk before \"fmt \" chunk (008)";
223 				return false;
224 			}
225 			fm->audio_block = fm->num_blocks;
226 		}
227 		if(!append_block_(fm, offset, 8 + (memcmp(buffer, "data", 4)? size : 0), error))
228 			return false;
229 		if(fseeko(f, size, SEEK_CUR) < 0) {
230 			if(error) *error = "invalid WAVE file: seek error (009)";
231 			return false;
232 		}
233 	}
234 	if(eof_offset != ftello(f)) {
235 		if(error) *error = "invalid WAVE file: unexpected EOF (010)";
236 		return false;
237 	}
238 	if(!fm->format_block) {
239 		if(error) *error = "invalid WAVE file: missing \"fmt \" chunk (011)";
240 		return false;
241 	}
242 	if(!fm->audio_block) {
243 		if(error) *error = "invalid WAVE file: missing \"data\" chunk (012)";
244 		return false;
245 	}
246 	return true;
247 }
248 
write_to_flac_(foreign_metadata_t * fm,FILE * fin,FILE * fout,FLAC__Metadata_SimpleIterator * it,const char ** error)249 static FLAC__bool write_to_flac_(foreign_metadata_t *fm, FILE *fin, FILE *fout, FLAC__Metadata_SimpleIterator *it, const char **error)
250 {
251 	FLAC__byte buffer[4];
252 	const unsigned ID_LEN = FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8;
253 	size_t block_num = 0;
254 	FLAC__ASSERT(sizeof(buffer) >= ID_LEN);
255 	while(block_num < fm->num_blocks) {
256 		/* find next matching padding block */
257 		do {
258 			/* 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 */
259 			if(!FLAC__metadata_simple_iterator_next(it)) {
260 				if(error) *error = "no matching PADDING block found (004)";
261 				return false;
262 			}
263 		} while(FLAC__metadata_simple_iterator_get_block_type(it) != FLAC__METADATA_TYPE_PADDING);
264 		if(FLAC__metadata_simple_iterator_get_block_length(it) != ID_LEN+fm->blocks[block_num].size) {
265 			if(error) *error = "PADDING block with wrong size found (005)";
266 			return false;
267 		}
268 		/* transfer chunk into APPLICATION block */
269 		/* first set up the file pointers */
270 		if(fseeko(fin, fm->blocks[block_num].offset, SEEK_SET) < 0) {
271 			if(error) *error = "seek failed in WAVE/AIFF file (006)";
272 			return false;
273 		}
274 		if(fseeko(fout, FLAC__metadata_simple_iterator_get_block_offset(it), SEEK_SET) < 0) {
275 			if(error) *error = "seek failed in FLAC file (007)";
276 			return false;
277 		}
278 		/* update the type */
279 		buffer[0] = FLAC__METADATA_TYPE_APPLICATION;
280 		if(FLAC__metadata_simple_iterator_is_last(it))
281 			buffer[0] |= 0x80; /*MAGIC number*/
282 		if(fwrite(buffer, 1, 1, fout) < 1) {
283 			if(error) *error = "write failed in FLAC file (008)";
284 			return false;
285 		}
286 		/* length stays the same so skip over it */
287 		if(fseeko(fout, FLAC__STREAM_METADATA_LENGTH_LEN/8, SEEK_CUR) < 0) {
288 			if(error) *error = "seek failed in FLAC file (009)";
289 			return false;
290 		}
291 		/* write the APPLICATION ID */
292 		memcpy(buffer, FLAC__FOREIGN_METADATA_APPLICATION_ID[fm->type], ID_LEN);
293 		if(fwrite(buffer, 1, ID_LEN, fout) < ID_LEN) {
294 			if(error) *error = "write failed in FLAC file (010)";
295 			return false;
296 		}
297 		/* transfer the foreign metadata */
298 		if(!copy_data_(fin, fout, fm->blocks[block_num].size, error, "read failed in WAVE/AIFF file (011)", "write failed in FLAC file (012)"))
299 			return false;
300 		block_num++;
301 	}
302 	return true;
303 }
304 
read_from_flac_(foreign_metadata_t * fm,FILE * f,FLAC__Metadata_SimpleIterator * it,const char ** error)305 static FLAC__bool read_from_flac_(foreign_metadata_t *fm, FILE *f, FLAC__Metadata_SimpleIterator *it, const char **error)
306 {
307 	FLAC__byte id[4], buffer[12];
308 	off_t offset;
309 	FLAC__bool type_found = false;
310 
311 	FLAC__ASSERT(FLAC__STREAM_METADATA_APPLICATION_ID_LEN == sizeof(id)*8);
312 
313 	while(FLAC__metadata_simple_iterator_next(it)) {
314 		if(FLAC__metadata_simple_iterator_get_block_type(it) != FLAC__METADATA_TYPE_APPLICATION)
315 			continue;
316 		if(!FLAC__metadata_simple_iterator_get_application_id(it, id)) {
317 			if(error) *error = "FLAC__metadata_simple_iterator_get_application_id() error (003)";
318 			return false;
319 		}
320 		if(memcmp(id, FLAC__FOREIGN_METADATA_APPLICATION_ID[fm->type], sizeof(id)))
321 			continue;
322 		offset = FLAC__metadata_simple_iterator_get_block_offset(it);
323 		/* skip over header and app ID */
324 		offset += (FLAC__STREAM_METADATA_IS_LAST_LEN + FLAC__STREAM_METADATA_TYPE_LEN + FLAC__STREAM_METADATA_LENGTH_LEN) / 8;
325 		offset += sizeof(id);
326 		/* look for format or audio blocks */
327 		if(fseek(f, offset, SEEK_SET) < 0) {
328 			if(error) *error = "seek error (004)";
329 			return false;
330 		}
331 		if(fread(buffer, 1, 4, f) != 4) {
332 			if(error) *error = "read error (005)";
333 			return false;
334 		}
335 		if(fm->num_blocks == 0) {
336 			if(fm->type == FOREIGN_BLOCK_TYPE__RIFF && 0 == memcmp(buffer, "RIFF", 4))
337 				type_found = true;
338 			else if(fm->type == FOREIGN_BLOCK_TYPE__AIFF && 0 == memcmp(buffer, "FORM", 4))
339 				type_found = true;
340 			else {
341 				if(error) *error = "unsupported foreign metadata found, may need newer FLAC decoder (005)";
342 				return false;
343 			}
344 		}
345 		else if(!type_found) {
346 			FLAC__ASSERT(0);
347 			/* double protection: */
348 			if(error) *error = "unsupported foreign metadata found, may need newer FLAC decoder (006)";
349 			return false;
350 		}
351 		else if(fm->type == FOREIGN_BLOCK_TYPE__RIFF) {
352 			if(!memcmp(buffer, "fmt ", 4)) {
353 				if(fm->format_block) {
354 					if(error) *error = "invalid WAVE metadata: multiple \"fmt \" chunks (007)";
355 					return false;
356 				}
357 				if(fm->audio_block) {
358 					if(error) *error = "invalid WAVE metadata: \"data\" chunk before \"fmt \" chunk (008)";
359 					return false;
360 				}
361 				fm->format_block = fm->num_blocks;
362 			}
363 			else if(!memcmp(buffer, "data", 4)) {
364 				if(fm->audio_block) {
365 					if(error) *error = "invalid WAVE metadata: multiple \"data\" chunks (009)";
366 					return false;
367 				}
368 				if(!fm->format_block) {
369 					if(error) *error = "invalid WAVE metadata: \"data\" chunk before \"fmt \" chunk (010)";
370 					return false;
371 				}
372 				fm->audio_block = fm->num_blocks;
373 			}
374 		}
375 		else if(fm->type == FOREIGN_BLOCK_TYPE__AIFF) {
376 			if(!memcmp(buffer, "COMM", 4)) {
377 				if(fm->format_block) {
378 					if(error) *error = "invalid AIFF metadata: multiple \"COMM\" chunks (011)";
379 					return false;
380 				}
381 				if(fm->audio_block) {
382 					if(error) *error = "invalid AIFF metadata: \"SSND\" chunk before \"COMM\" chunk (012)";
383 					return false;
384 				}
385 				fm->format_block = fm->num_blocks;
386 			}
387 			else if(!memcmp(buffer, "SSND", 4)) {
388 				if(fm->audio_block) {
389 					if(error) *error = "invalid AIFF metadata: multiple \"SSND\" chunks (013)";
390 					return false;
391 				}
392 				if(!fm->format_block) {
393 					if(error) *error = "invalid AIFF metadata: \"SSND\" chunk before \"COMM\" chunk (014)";
394 					return false;
395 				}
396 				fm->audio_block = fm->num_blocks;
397 				/* read SSND offset size */
398 				if(fread(buffer+4, 1, 8, f) != 8) {
399 					if(error) *error = "read error (015)";
400 					return false;
401 				}
402 				fm->ssnd_offset_size = unpack32be_(buffer+8);
403 			}
404 		}
405 		else {
406 			FLAC__ASSERT(0);
407 			/* double protection: */
408 			if(error) *error = "unsupported foreign metadata found, may need newer FLAC decoder (016)";
409 			return false;
410 		}
411 		if(!append_block_(fm, offset, FLAC__metadata_simple_iterator_get_block_length(it)-sizeof(id), error))
412 			return false;
413 	}
414 	if(!type_found) {
415 		if(error) *error = "no foreign metadata found (017)";
416 		return false;
417 	}
418 	if(!fm->format_block) {
419 		if(error) *error = fm->type==FOREIGN_BLOCK_TYPE__RIFF? "invalid WAVE file: missing \"fmt \" chunk (018)" : "invalid AIFF file: missing \"COMM\" chunk (018)";
420 		return false;
421 	}
422 	if(!fm->audio_block) {
423 		if(error) *error = fm->type==FOREIGN_BLOCK_TYPE__RIFF? "invalid WAVE file: missing \"data\" chunk (019)" : "invalid AIFF file: missing \"SSND\" chunk (019)";
424 		return false;
425 	}
426 	return true;
427 }
428 
write_to_iff_(foreign_metadata_t * fm,FILE * fin,FILE * fout,off_t offset1,off_t offset2,off_t offset3,const char ** error)429 static FLAC__bool write_to_iff_(foreign_metadata_t *fm, FILE *fin, FILE *fout, off_t offset1, off_t offset2, off_t offset3, const char **error)
430 {
431 	size_t i;
432 	if(fseeko(fout, offset1, SEEK_SET) < 0) {
433 		if(error) *error = "seek failed in WAVE/AIFF file (002)";
434 		return false;
435 	}
436 	for(i = 1; i < fm->format_block; i++) {
437 		if(fseeko(fin, fm->blocks[i].offset, SEEK_SET) < 0) {
438 			if(error) *error = "seek failed in FLAC file (003)";
439 			return false;
440 		}
441 		if(!copy_data_(fin, fout, fm->blocks[i].size, error, "read failed in WAVE/AIFF file (004)", "write failed in FLAC file (005)"))
442 			return false;
443 	}
444 	if(fseeko(fout, offset2, SEEK_SET) < 0) {
445 		if(error) *error = "seek failed in WAVE/AIFF file (006)";
446 		return false;
447 	}
448 	for(i = fm->format_block+1; i < fm->audio_block; i++) {
449 		if(fseeko(fin, fm->blocks[i].offset, SEEK_SET) < 0) {
450 			if(error) *error = "seek failed in FLAC file (007)";
451 			return false;
452 		}
453 		if(!copy_data_(fin, fout, fm->blocks[i].size, error, "read failed in WAVE/AIFF file (008)", "write failed in FLAC file (009)"))
454 			return false;
455 	}
456 	if(fseeko(fout, offset3, SEEK_SET) < 0) {
457 		if(error) *error = "seek failed in WAVE/AIFF file (010)";
458 		return false;
459 	}
460 	for(i = fm->audio_block+1; i < fm->num_blocks; i++) {
461 		if(fseeko(fin, fm->blocks[i].offset, SEEK_SET) < 0) {
462 			if(error) *error = "seek failed in FLAC file (011)";
463 			return false;
464 		}
465 		if(!copy_data_(fin, fout, fm->blocks[i].size, error, "read failed in WAVE/AIFF file (012)", "write failed in FLAC file (013)"))
466 			return false;
467 	}
468 	return true;
469 }
470 
flac__foreign_metadata_new(foreign_block_type_t type)471 foreign_metadata_t *flac__foreign_metadata_new(foreign_block_type_t type)
472 {
473 	foreign_metadata_t *x = (foreign_metadata_t*)calloc(sizeof(foreign_metadata_t), 1);
474 	if(x)
475 		x->type = type;
476 	return x;
477 }
478 
flac__foreign_metadata_delete(foreign_metadata_t * fm)479 void flac__foreign_metadata_delete(foreign_metadata_t *fm)
480 {
481 	if(fm) {
482 		if(fm->blocks)
483 			free(fm->blocks);
484 		free(fm);
485 	}
486 }
487 
flac__foreign_metadata_read_from_aiff(foreign_metadata_t * fm,const char * filename,const char ** error)488 FLAC__bool flac__foreign_metadata_read_from_aiff(foreign_metadata_t *fm, const char *filename, const char **error)
489 {
490 	FLAC__bool ok;
491 	FILE *f = fopen(filename, "rb");
492 	if(!f) {
493 		if(error) *error = "can't open AIFF file for reading (000)";
494 		return false;
495 	}
496 	ok = read_from_aiff_(fm, f, error);
497 	fclose(f);
498 	return ok;
499 }
500 
flac__foreign_metadata_read_from_wave(foreign_metadata_t * fm,const char * filename,const char ** error)501 FLAC__bool flac__foreign_metadata_read_from_wave(foreign_metadata_t *fm, const char *filename, const char **error)
502 {
503 	FLAC__bool ok;
504 	FILE *f = fopen(filename, "rb");
505 	if(!f) {
506 		if(error) *error = "can't open WAVE file for reading (000)";
507 		return false;
508 	}
509 	ok = read_from_wave_(fm, f, error);
510 	fclose(f);
511 	return ok;
512 }
513 
flac__foreign_metadata_write_to_flac(foreign_metadata_t * fm,const char * infilename,const char * outfilename,const char ** error)514 FLAC__bool flac__foreign_metadata_write_to_flac(foreign_metadata_t *fm, const char *infilename, const char *outfilename, const char **error)
515 {
516 	FLAC__bool ok;
517 	FILE *fin, *fout;
518 	FLAC__Metadata_SimpleIterator *it = FLAC__metadata_simple_iterator_new();
519 	if(!it) {
520 		if(error) *error = "out of memory (000)";
521 		return false;
522 	}
523 	if(!FLAC__metadata_simple_iterator_init(it, outfilename, /*read_only=*/true, /*preserve_file_stats=*/false)) {
524 		if(error) *error = "can't initialize iterator (001)";
525 		FLAC__metadata_simple_iterator_delete(it);
526 		return false;
527 	}
528 	if(0 == (fin = fopen(infilename, "rb"))) {
529 		if(error) *error = "can't open WAVE/AIFF file for reading (002)";
530 		FLAC__metadata_simple_iterator_delete(it);
531 		return false;
532 	}
533 	if(0 == (fout = fopen(outfilename, "r+b"))) {
534 		if(error) *error = "can't open FLAC file for updating (003)";
535 		FLAC__metadata_simple_iterator_delete(it);
536 		fclose(fin);
537 		return false;
538 	}
539 	ok = write_to_flac_(fm, fin, fout, it, error);
540 	FLAC__metadata_simple_iterator_delete(it);
541 	fclose(fin);
542 	fclose(fout);
543 	return ok;
544 }
545 
flac__foreign_metadata_read_from_flac(foreign_metadata_t * fm,const char * filename,const char ** error)546 FLAC__bool flac__foreign_metadata_read_from_flac(foreign_metadata_t *fm, const char *filename, const char **error)
547 {
548 	FLAC__bool ok;
549 	FILE *f;
550 	FLAC__Metadata_SimpleIterator *it = FLAC__metadata_simple_iterator_new();
551 	if(!it) {
552 		if(error) *error = "out of memory (000)";
553 		return false;
554 	}
555 	if(!FLAC__metadata_simple_iterator_init(it, filename, /*read_only=*/true, /*preserve_file_stats=*/false)) {
556 		if(error) *error = "can't initialize iterator (001)";
557 		FLAC__metadata_simple_iterator_delete(it);
558 		return false;
559 	}
560 	if(0 == (f = fopen(filename, "rb"))) {
561 		if(error) *error = "can't open FLAC file for reading (002)";
562 		FLAC__metadata_simple_iterator_delete(it);
563 		return false;
564 	}
565 	ok = read_from_flac_(fm, f, it, error);
566 	FLAC__metadata_simple_iterator_delete(it);
567 	fclose(f);
568 	return ok;
569 }
570 
flac__foreign_metadata_write_to_iff(foreign_metadata_t * fm,const char * infilename,const char * outfilename,off_t offset1,off_t offset2,off_t offset3,const char ** error)571 FLAC__bool flac__foreign_metadata_write_to_iff(foreign_metadata_t *fm, const char *infilename, const char *outfilename, off_t offset1, off_t offset2, off_t offset3, const char **error)
572 {
573 	FLAC__bool ok;
574 	FILE *fin, *fout;
575 	if(0 == (fin = fopen(infilename, "rb"))) {
576 		if(error) *error = "can't open FLAC file for reading (000)";
577 		return false;
578 	}
579 	if(0 == (fout = fopen(outfilename, "r+b"))) {
580 		if(error) *error = "can't open WAVE/AIFF file for updating (001)";
581 		fclose(fin);
582 		return false;
583 	}
584 	ok = write_to_iff_(fm, fin, fout, offset1, offset2, offset3, error);
585 	fclose(fin);
586 	fclose(fout);
587 	return ok;
588 }
589