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