9487e9b3898b662f6d3ffae6665c41bb3d089d8e
[platform/upstream/flac.git] / src / 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 "foreign_metadata.h"
36
37 #ifdef min
38 #undef min
39 #endif
40 #define min(x,y) ((x)<(y)?(x):(y))
41
42
43 static const char *FLAC__FOREIGN_METADATA_APPLICATION_ID[2] = { "AIFF" , "RIFF" };
44
45 static FLAC__uint32 unpack32be_(const FLAC__byte *b)
46 {
47         return ((FLAC__uint32)b[0]<<24) + ((FLAC__uint32)b[1]<<16) + ((FLAC__uint32)b[2]<<8) + (FLAC__uint32)b[3];
48 }
49
50 static FLAC__uint32 unpack32le_(const FLAC__byte *b)
51 {
52         return (FLAC__uint32)b[0] + ((FLAC__uint32)b[1]<<8) + ((FLAC__uint32)b[2]<<16) + ((FLAC__uint32)b[3]<<24);
53 }
54
55 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)
56 {
57         static FLAC__byte buffer[4096];
58         size_t left;
59         for(left = size; left > 0; ) {
60                 size_t need = min(sizeof(buffer), left);
61                 if(fread(buffer, 1, need, fin) < need) {
62                         if(error) *error = read_error;
63                         return false;
64                 }
65                 if(fwrite(buffer, 1, need, fout) < need) {
66                         if(error) *error = write_error;
67                         return false;
68                 }
69                 left -= need;
70         }
71         return true;
72 }
73
74 static FLAC__bool append_block_(foreign_metadata_t *fm, off_t offset, FLAC__uint32 size, const char **error)
75 {
76         foreign_block_t *fb = realloc(fm->blocks, sizeof(foreign_block_t) * (fm->num_blocks+1));
77         if(fb) {
78                 fb[fm->num_blocks].offset = offset;
79                 fb[fm->num_blocks].size = size;
80                 fm->num_blocks++;
81                 fm->blocks = fb;
82 /*fprintf(stderr,"@@@@@@  appended: block#%u offset=%d size=%u\n",fm->num_blocks-1,(int)fm->blocks[fm->num_blocks-1].offset,(unsigned)fm->blocks[fm->num_blocks-1].size);*/
83                 return true;
84         }
85         if(error) *error = "out of memory";
86         return false;
87 }
88
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 /*fprintf(stderr,"@@@@@@ off=%d eof=%d\n",(int)offset,(int)eof_offset);*/
105         while(!feof(f)) {
106                 FLAC__uint32 size;
107                 if((offset = ftello(f)) < 0) {
108                         if(error) *error = "ftello() error (003)";
109                         return false;
110                 }
111                 if((size = fread(buffer, 1, 8, f)) < 8) {
112                         if(size == 0 && feof(f))
113                                 break;
114                         if(error) *error = "invalid AIFF file (004)";
115                         return false;
116                 }
117                 size = unpack32be_(buffer+4);
118                 /* check if pad byte needed */
119                 if(size & 1)
120                         size++;
121                 if(!memcmp(buffer, "COMM", 4)) {
122                         if(fm->format_block) {
123                                 if(error) *error = "invalid AIFF file: multiple \"COMM\" chunks (005)";
124                                 return false;
125                         }
126                         if(fm->audio_block) {
127                                 if(error) *error = "invalid AIFF file: \"SSND\" chunk before \"COMM\" chunk (006)";
128                                 return false;
129                         }
130                         fm->format_block = fm->num_blocks;
131                 }
132                 else if(!memcmp(buffer, "SSND", 4)) {
133                         if(fm->audio_block) {
134                                 if(error) *error = "invalid AIFF file: multiple \"SSND\" chunks (007)";
135                                 return false;
136                         }
137                         if(!fm->format_block) {
138                                 if(error) *error = "invalid AIFF file: \"SSND\" chunk before \"COMM\" chunk (008)";
139                                 return false;
140                         }
141                         fm->audio_block = fm->num_blocks;
142                         /* read #offset bytes */
143                         if(fread(buffer+8, 1, 4, f) < 4) {
144                                 if(error) *error = "invalid AIFF file (009)";
145                                 return false;
146                         }
147                         fm->ssnd_offset_size = unpack32be_(buffer+8);
148                         if(fseeko(f, -4, SEEK_CUR) < 0) {
149                                 if(error) *error = "invalid AIFF file: seek error (010)";
150                                 return false;
151                         }
152                 }
153                 if(!append_block_(fm, offset, 8 + (memcmp(buffer, "SSND", 4)? size : 8 + fm->ssnd_offset_size), error))
154                         return false;
155 /*fprintf(stderr,"@@@@@@ chunk=%c%c%c%c offset=%d size=%d\n",buffer[0],buffer[1],buffer[2],buffer[3],(int)offset,8+(int)size);*/
156                 if(fseeko(f, size, SEEK_CUR) < 0) {
157                         if(error) *error = "invalid AIFF file: seek error (011)";
158                         return false;
159                 }
160         }
161         if(eof_offset != ftello(f)) {
162                 if(error) *error = "invalid AIFF file: unexpected EOF (012)";
163                 return false;
164         }
165         if(!fm->format_block) {
166                 if(error) *error = "invalid AIFF file: missing \"COMM\" chunk (013)";
167                 return false;
168         }
169         if(!fm->audio_block) {
170                 if(error) *error = "invalid AIFF file: missing \"SSND\" chunk (014)";
171                 return false;
172         }
173         return true;
174 }
175
176 static FLAC__bool read_from_wave_(foreign_metadata_t *fm, FILE *f, const char **error)
177 {
178         FLAC__byte buffer[12];
179         off_t offset, eof_offset;
180         if((offset = ftello(f)) < 0) {
181                 if(error) *error = "ftello() error (001)";
182                 return false;
183         }
184         if(fread(buffer, 1, 12, f) < 12 || memcmp(buffer, "RIFF", 4) || memcmp(buffer+8, "WAVE", 4)) {
185                 if(error) *error = "unsupported RIFF layout (002)";
186                 return false;
187         }
188         if(!append_block_(fm, offset, 12, error))
189                 return false;
190         eof_offset = 8 + unpack32le_(buffer+4);
191 /*fprintf(stderr,"@@@@@@ off=%d eof=%d\n",(int)offset,(int)eof_offset);*/
192         while(!feof(f)) {
193                 FLAC__uint32 size;
194                 if((offset = ftello(f)) < 0) {
195                         if(error) *error = "ftello() error (003)";
196                         return false;
197                 }
198                 if((size = fread(buffer, 1, 8, f)) < 8) {
199                         if(size == 0 && feof(f))
200                                 break;
201                         if(error) *error = "invalid WAVE file (004)";
202                         return false;
203                 }
204                 size = unpack32le_(buffer+4);
205                 /* check if pad byte needed */
206                 if(size & 1)
207                         size++;
208                 if(!memcmp(buffer, "fmt ", 4)) {
209                         if(fm->format_block) {
210                                 if(error) *error = "invalid WAVE file: multiple \"fmt \" chunks (005)";
211                                 return false;
212                         }
213                         if(fm->audio_block) {
214                                 if(error) *error = "invalid WAVE file: \"data\" chunk before \"fmt \" chunk (006)";
215                                 return false;
216                         }
217                         fm->format_block = fm->num_blocks;
218                 }
219                 else if(!memcmp(buffer, "data", 4)) {
220                         if(fm->audio_block) {
221                                 if(error) *error = "invalid WAVE file: multiple \"data\" chunks (007)";
222                                 return false;
223                         }
224                         if(!fm->format_block) {
225                                 if(error) *error = "invalid WAVE file: \"data\" chunk before \"fmt \" chunk (008)";
226                                 return false;
227                         }
228                         fm->audio_block = fm->num_blocks;
229                 }
230                 if(!append_block_(fm, offset, 8 + (memcmp(buffer, "data", 4)? size : 0), error))
231                         return false;
232 /*fprintf(stderr,"@@@@@@ chunk=%c%c%c%c offset=%d size=%d\n",buffer[0],buffer[1],buffer[2],buffer[3],(int)offset,8+(int)size);*/
233                 if(fseeko(f, size, SEEK_CUR) < 0) {
234                         if(error) *error = "invalid WAVE file: seek error (009)";
235                         return false;
236                 }
237         }
238         if(eof_offset != ftello(f)) {
239                 if(error) *error = "invalid WAVE file: unexpected EOF (010)";
240                 return false;
241         }
242         if(!fm->format_block) {
243                 if(error) *error = "invalid WAVE file: missing \"fmt \" chunk (011)";
244                 return false;
245         }
246         if(!fm->audio_block) {
247                 if(error) *error = "invalid WAVE file: missing \"data\" chunk (012)";
248                 return false;
249         }
250         return true;
251 }
252
253 static FLAC__bool write_to_flac_(foreign_metadata_t *fm, FILE *fin, FILE *fout, FLAC__Metadata_SimpleIterator *it, const char **error)
254 {
255         FLAC__byte buffer[4];
256         const unsigned ID_LEN = FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8;
257         size_t block_num = 0;
258         FLAC__ASSERT(sizeof(buffer) >= ID_LEN);
259         while(block_num < fm->num_blocks) {
260                 /* find next matching padding block */
261                 do {
262                         /* 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 */
263                         if(!FLAC__metadata_simple_iterator_next(it)) {
264                                 if(error) *error = "no matching PADDING block found (004)";
265                                 return false;
266                         }
267                 } while(FLAC__metadata_simple_iterator_get_block_type(it) != FLAC__METADATA_TYPE_PADDING);
268                 if(FLAC__metadata_simple_iterator_get_block_length(it) != ID_LEN+fm->blocks[block_num].size) {
269                         if(error) *error = "PADDING block with wrong size found (005)";
270                         return false;
271                 }
272 /*fprintf(stderr,"@@@@@@ flac offset = %d\n",(int)FLAC__metadata_simple_iterator_get_block_offset(it));*/
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 }