3015f1d9c588c6ad6a57e29da5d0f1862dffe2fc
[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,2008,2009  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 along
15  * with this program; if not, write to the Free Software Foundation, Inc.,
16  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17  */
18
19 #if HAVE_CONFIG_H
20 #  include <config.h>
21 #endif
22
23 #include <stdio.h> /* for FILE etc. */
24 #include <stdlib.h> /* for calloc() etc. */
25 #include <string.h> /* for memcmp() etc. */
26 #include "FLAC/assert.h"
27 #include "FLAC/metadata.h"
28 #include "share/alloc.h"
29 #include "share/compat.h"
30 #include "foreign_metadata.h"
31
32 #ifdef min
33 #undef min
34 #endif
35 #define min(x,y) ((x)<(y)?(x):(y))
36
37
38 static const char *FLAC__FOREIGN_METADATA_APPLICATION_ID[3] = { "aiff" , "riff", "w64 " };
39
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
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
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 */
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 static FLAC__bool append_block_(foreign_metadata_t *fm, FLAC__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
89 static FLAC__bool read_from_aiff_(foreign_metadata_t *fm, FILE *f, const char **error)
90 {
91         FLAC__byte buffer[12];
92         FLAC__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 = (FLAC__off_t)8 + (FLAC__off_t)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                         /* WATCHOUT: For SSND we ignore the blockSize and are not saving any
152                          * unaligned part at the end of the chunk.  In retrospect it is pretty
153                          * pointless to save the unaligned data before the PCM but now it is
154                          * done and cast in stone.
155                          */
156                 }
157                 if(!append_block_(fm, offset, 8 + (memcmp(buffer, "SSND", 4)? size : 8 + fm->ssnd_offset_size), error))
158                         return false;
159                 /* skip to next chunk */
160                 if(fseeko(f, size, SEEK_CUR) < 0) {
161                         if(error) *error = "invalid AIFF file: seek error (011)";
162                         return false;
163                 }
164         }
165         if(eof_offset != ftello(f)) {
166                 if(error) *error = "invalid AIFF file: unexpected EOF (012)";
167                 return false;
168         }
169         if(!fm->format_block) {
170                 if(error) *error = "invalid AIFF file: missing \"COMM\" chunk (013)";
171                 return false;
172         }
173         if(!fm->audio_block) {
174                 if(error) *error = "invalid AIFF file: missing \"SSND\" chunk (014)";
175                 return false;
176         }
177         return true;
178 }
179
180 static FLAC__bool read_from_wave_(foreign_metadata_t *fm, FILE *f, const char **error)
181 {
182         FLAC__byte buffer[12];
183         FLAC__off_t offset, eof_offset = -1, ds64_data_size = -1;
184         if((offset = ftello(f)) < 0) {
185                 if(error) *error = "ftello() error (001)";
186                 return false;
187         }
188         if(fread(buffer, 1, 12, f) < 12 || (memcmp(buffer, "RIFF", 4) && memcmp(buffer, "RF64", 4)) || memcmp(buffer+8, "WAVE", 4)) {
189                 if(error) *error = "unsupported RIFF layout (002)";
190                 return false;
191         }
192         if(!memcmp(buffer, "RF64", 4))
193                 fm->is_rf64 = true;
194         if(fm->is_rf64 && sizeof(FLAC__off_t) < 8) {
195                 if(error) *error = "RF64 is not supported on this compile (r00)";
196                 return false;
197         }
198         if(!append_block_(fm, offset, 12, error))
199                 return false;
200         if(!fm->is_rf64 || unpack32le_(buffer+4) != 0xffffffffu)
201                 eof_offset = (FLAC__off_t)8 + (FLAC__off_t)unpack32le_(buffer+4);
202         while(!feof(f)) {
203                 FLAC__uint32 size;
204                 if((offset = ftello(f)) < 0) {
205                         if(error) *error = "ftello() error (003)";
206                         return false;
207                 }
208                 if((size = fread(buffer, 1, 8, f)) < 8) {
209                         if(size == 0 && feof(f))
210                                 break;
211                         if(error) *error = "invalid WAVE file (004)";
212                         return false;
213                 }
214                 size = unpack32le_(buffer+4);
215                 /* check if pad byte needed */
216                 if(size & 1)
217                         size++;
218                 if(!memcmp(buffer, "fmt ", 4)) {
219                         if(fm->format_block) {
220                                 if(error) *error = "invalid WAVE file: multiple \"fmt \" chunks (005)";
221                                 return false;
222                         }
223                         if(fm->audio_block) {
224                                 if(error) *error = "invalid WAVE file: \"data\" chunk before \"fmt \" chunk (006)";
225                                 return false;
226                         }
227                         fm->format_block = fm->num_blocks;
228                 }
229                 else if(!memcmp(buffer, "data", 4)) {
230                         if(fm->audio_block) {
231                                 if(error) *error = "invalid WAVE file: multiple \"data\" chunks (007)";
232                                 return false;
233                         }
234                         if(!fm->format_block) {
235                                 if(error) *error = "invalid WAVE file: \"data\" chunk before \"fmt \" chunk (008)";
236                                 return false;
237                         }
238                         fm->audio_block = fm->num_blocks;
239                         if(fm->is_rf64 && fm->num_blocks < 2) {
240                                 if(error) *error = "invalid RF64 file: \"data\" chunk before \"ds64\" chunk (r01)";
241                                 return false;
242                         }
243                 }
244                 if(!append_block_(fm, offset, 8 + (memcmp(buffer, "data", 4)? size : 0), error))
245                         return false;
246                 /* parse ds64 chunk if necessary */
247                 if(fm->is_rf64 && fm->num_blocks == 2) {
248                         FLAC__byte buffer2[7*4];
249                         if(memcmp(buffer, "ds64", 4)) {
250                                 if(error) *error = "invalid RF64 file: \"ds64\" chunk does not immediately follow \"WAVE\" marker (r02)";
251                                 return false;
252                         }
253                         /* unpack the size again since we don't want the padding byte effect */
254                         size = unpack32le_(buffer+4);
255                         if(size < sizeof(buffer2)) {
256                                 if(error) *error = "invalid RF64 file: \"ds64\" chunk size is < 28 (r03)";
257                                 return false;
258                         }
259                         if(size > sizeof(buffer2)) {
260                                 if(error) *error = "RF64 file has \"ds64\" chunk with extra size table, which is not currently supported (r04)";
261                                 return false;
262                         }
263                         if(fread(buffer2, 1, sizeof(buffer2), f) < sizeof(buffer2)) {
264                                 if(error) *error = "unexpected EOF reading \"ds64\" chunk data in RF64 file (r05)";
265                                 return false;
266                         }
267                         ds64_data_size = (FLAC__off_t)unpack64le_(buffer2+8);
268                         if(ds64_data_size == (FLAC__off_t)(-1)) {
269                                 if(error) *error = "RF64 file has \"ds64\" chunk with data size == -1 (r08)";
270                                 return false;
271                         }
272                         /* check if pad byte needed */
273                         if(ds64_data_size & 1)
274                                 ds64_data_size++;
275                         /* @@@ [2^63 limit] */
276                         if(ds64_data_size < 0) {
277                                 if(error) *error = "RF64 file too large (r09)";
278                                 return false;
279                         }
280                         if(unpack32le_(buffer2+24)) {
281                                 if(error) *error = "RF64 file has \"ds64\" chunk with extra size table, which is not currently supported (r06)";
282                                 return false;
283                         }
284                         eof_offset = (FLAC__off_t)8 + (FLAC__off_t)unpack64le_(buffer2);
285                         /* @@@ [2^63 limit] */
286                         if((FLAC__off_t)unpack64le_(buffer2) < 0 || eof_offset < 0) {
287                                 if(error) *error = "RF64 file too large (r07)";
288                                 return false;
289                         }
290                 }
291                 else { /* skip to next chunk */
292                         if(fm->is_rf64 && !memcmp(buffer, "data", 4) && unpack32le_(buffer+4) == 0xffffffffu) {
293                                 if(fseeko(f, ds64_data_size, SEEK_CUR) < 0) {
294                                         if(error) *error = "invalid RF64 file: seek error (r10)";
295                                         return false;
296                                 }
297                         }
298                         else {
299                                 if(fseeko(f, size, SEEK_CUR) < 0) {
300                                         if(error) *error = "invalid WAVE file: seek error (009)";
301                                         return false;
302                                 }
303                         }
304                 }
305         }
306         if(fm->is_rf64 && eof_offset == (FLAC__off_t)(-1)) {
307                 if(error) *error = "invalid RF64 file: all RIFF sizes are -1 (r11)";
308                 return false;
309         }
310         if(eof_offset != ftello(f)) {
311                 if(error) *error = "invalid WAVE file: unexpected EOF (010)";
312                 return false;
313         }
314         if(!fm->format_block) {
315                 if(error) *error = "invalid WAVE file: missing \"fmt \" chunk (011)";
316                 return false;
317         }
318         if(!fm->audio_block) {
319                 if(error) *error = "invalid WAVE file: missing \"data\" chunk (012)";
320                 return false;
321         }
322         return true;
323 }
324
325 static FLAC__bool read_from_wave64_(foreign_metadata_t *fm, FILE *f, const char **error)
326 {
327         FLAC__byte buffer[40];
328         FLAC__off_t offset, eof_offset = -1;
329         if((offset = ftello(f)) < 0) {
330                 if(error) *error = "ftello() error (001)";
331                 return false;
332         }
333         if(
334                 fread(buffer, 1, 40, f) < 40 ||
335                 /* RIFF GUID 66666972-912E-11CF-A5D6-28DB04C10000 */
336                 memcmp(buffer, "\x72\x69\x66\x66\x2E\x91\xCF\x11\xA5\xD6\x28\xDB\x04\xC1\x00\x00", 16) ||
337                 /* WAVE GUID 65766177-ACF3-11D3-8CD1-00C04F8EDB8A */
338                 memcmp(buffer+24, "\x77\x61\x76\x65\xF3\xAC\xD3\x11\x8C\xD1\x00\xC0\x4F\x8E\xDB\x8A", 16)
339         ) {
340                 if(error) *error = "unsupported Wave64 layout (002)";
341                 return false;
342         }
343         if(sizeof(FLAC__off_t) < 8) {
344                 if(error) *error = "Wave64 is not supported on this compile (r00)";
345                 return false;
346         }
347         if(!append_block_(fm, offset, 40, error))
348                 return false;
349         eof_offset = (FLAC__off_t)unpack64le_(buffer+16); /*@@@ [2^63 limit] */
350         while(!feof(f)) {
351                 FLAC__uint64 size;
352                 if((offset = ftello(f)) < 0) {
353                         if(error) *error = "ftello() error (003)";
354                         return false;
355                 }
356                 if((size = fread(buffer, 1, 24, f)) < 24) {
357                         if(size == 0 && feof(f))
358                                 break;
359                         if(error) *error = "invalid Wave64 file (004)";
360                         return false;
361                 }
362                 size = unpack64le_(buffer+16);
363                 /* check if pad bytes needed */
364                 if(size & 7)
365                         size = (size+7) & (~((FLAC__uint64)7));
366                 /* fmt GUID 20746D66-ACF3-11D3-8CD1-00C04F8EDB8A */
367                 if(!memcmp(buffer, "\x66\x6D\x74\x20\xF3\xAC\xD3\x11\x8C\xD1\x00\xC0\x4F\x8E\xDB\x8A", 16)) {
368                         if(fm->format_block) {
369                                 if(error) *error = "invalid Wave64 file: multiple \"fmt \" chunks (005)";
370                                 return false;
371                         }
372                         if(fm->audio_block) {
373                                 if(error) *error = "invalid Wave64 file: \"data\" chunk before \"fmt \" chunk (006)";
374                                 return false;
375                         }
376                         fm->format_block = fm->num_blocks;
377                 }
378                 /* data GUID 61746164-ACF3-11D3-8CD1-00C04F8EDB8A */
379                 else if(!memcmp(buffer, "\x64\x61\x74\x61\xF3\xAC\xD3\x11\x8C\xD1\x00\xC0\x4F\x8E\xDB\x8A", 16)) {
380                         if(fm->audio_block) {
381                                 if(error) *error = "invalid Wave64 file: multiple \"data\" chunks (007)";
382                                 return false;
383                         }
384                         if(!fm->format_block) {
385                                 if(error) *error = "invalid Wave64 file: \"data\" chunk before \"fmt \" chunk (008)";
386                                 return false;
387                         }
388                         fm->audio_block = fm->num_blocks;
389                 }
390                 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))
391                         return false;
392                 /* skip to next chunk */
393                 if(fseeko(f, size-24, SEEK_CUR) < 0) {
394                         if(error) *error = "invalid Wave64 file: seek error (009)";
395                         return false;
396                 }
397         }
398         if(eof_offset != ftello(f)) {
399                 if(error) *error = "invalid Wave64 file: unexpected EOF (010)";
400                 return false;
401         }
402         if(!fm->format_block) {
403                 if(error) *error = "invalid Wave64 file: missing \"fmt \" chunk (011)";
404                 return false;
405         }
406         if(!fm->audio_block) {
407                 if(error) *error = "invalid Wave64 file: missing \"data\" chunk (012)";
408                 return false;
409         }
410         return true;
411 }
412
413 static FLAC__bool write_to_flac_(foreign_metadata_t *fm, FILE *fin, FILE *fout, FLAC__Metadata_SimpleIterator *it, const char **error)
414 {
415         FLAC__byte buffer[4];
416         const unsigned ID_LEN = FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8;
417         size_t block_num = 0;
418         FLAC__ASSERT(sizeof(buffer) >= ID_LEN);
419         while(block_num < fm->num_blocks) {
420                 /* find next matching padding block */
421                 do {
422                         /* 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 */
423                         if(!FLAC__metadata_simple_iterator_next(it)) {
424                                 if(error) *error = "no matching PADDING block found (004)";
425                                 return false;
426                         }
427                 } while(FLAC__metadata_simple_iterator_get_block_type(it) != FLAC__METADATA_TYPE_PADDING);
428                 if(FLAC__metadata_simple_iterator_get_block_length(it) != ID_LEN+fm->blocks[block_num].size) {
429                         if(error) *error = "PADDING block with wrong size found (005)";
430                         return false;
431                 }
432                 /* transfer chunk into APPLICATION block */
433                 /* first set up the file pointers */
434                 if(fseeko(fin, fm->blocks[block_num].offset, SEEK_SET) < 0) {
435                         if(error) *error = "seek failed in WAVE/AIFF file (006)";
436                         return false;
437                 }
438                 if(fseeko(fout, FLAC__metadata_simple_iterator_get_block_offset(it), SEEK_SET) < 0) {
439                         if(error) *error = "seek failed in FLAC file (007)";
440                         return false;
441                 }
442                 /* update the type */
443                 buffer[0] = FLAC__METADATA_TYPE_APPLICATION;
444                 if(FLAC__metadata_simple_iterator_is_last(it))
445                         buffer[0] |= 0x80; /*MAGIC number*/
446                 if(fwrite(buffer, 1, 1, fout) < 1) {
447                         if(error) *error = "write failed in FLAC file (008)";
448                         return false;
449                 }
450                 /* length stays the same so skip over it */
451                 if(fseeko(fout, FLAC__STREAM_METADATA_LENGTH_LEN/8, SEEK_CUR) < 0) {
452                         if(error) *error = "seek failed in FLAC file (009)";
453                         return false;
454                 }
455                 /* write the APPLICATION ID */
456                 memcpy(buffer, FLAC__FOREIGN_METADATA_APPLICATION_ID[fm->type], ID_LEN);
457                 if(fwrite(buffer, 1, ID_LEN, fout) < ID_LEN) {
458                         if(error) *error = "write failed in FLAC file (010)";
459                         return false;
460                 }
461                 /* transfer the foreign metadata */
462                 if(!copy_data_(fin, fout, fm->blocks[block_num].size, error, "read failed in WAVE/AIFF file (011)", "write failed in FLAC file (012)"))
463                         return false;
464                 block_num++;
465         }
466         return true;
467 }
468
469 static FLAC__bool read_from_flac_(foreign_metadata_t *fm, FILE *f, FLAC__Metadata_SimpleIterator *it, const char **error)
470 {
471         FLAC__byte id[4], buffer[12];
472         FLAC__off_t offset;
473         FLAC__bool type_found = false, ds64_found = false;
474
475         FLAC__ASSERT(FLAC__STREAM_METADATA_APPLICATION_ID_LEN == sizeof(id)*8);
476
477         while(FLAC__metadata_simple_iterator_next(it)) {
478                 if(FLAC__metadata_simple_iterator_get_block_type(it) != FLAC__METADATA_TYPE_APPLICATION)
479                         continue;
480                 if(!FLAC__metadata_simple_iterator_get_application_id(it, id)) {
481                         if(error) *error = "FLAC__metadata_simple_iterator_get_application_id() error (002)";
482                         return false;
483                 }
484                 if(memcmp(id, FLAC__FOREIGN_METADATA_APPLICATION_ID[fm->type], sizeof(id)))
485                         continue;
486                 offset = FLAC__metadata_simple_iterator_get_block_offset(it);
487                 /* skip over header and app ID */
488                 offset += (FLAC__STREAM_METADATA_IS_LAST_LEN + FLAC__STREAM_METADATA_TYPE_LEN + FLAC__STREAM_METADATA_LENGTH_LEN) / 8;
489                 offset += sizeof(id);
490                 /* look for format or audio blocks */
491                 if(fseeko(f, offset, SEEK_SET) < 0) {
492                         if(error) *error = "seek error (003)";
493                         return false;
494                 }
495                 if(fread(buffer, 1, 4, f) != 4) {
496                         if(error) *error = "read error (004)";
497                         return false;
498                 }
499                 if(fm->num_blocks == 0) { /* first block? */
500                         fm->is_rf64 = 0 == memcmp(buffer, "RF64", 4);
501                         if(fm->type == FOREIGN_BLOCK_TYPE__RIFF && (0 == memcmp(buffer, "RIFF", 4) || fm->is_rf64))
502                                 type_found = true;
503                         else if(fm->type == FOREIGN_BLOCK_TYPE__WAVE64 && 0 == memcmp(buffer, "riff", 4)) /* use first 4 bytes instead of whole GUID */
504                                 type_found = true;
505                         else if(fm->type == FOREIGN_BLOCK_TYPE__AIFF && 0 == memcmp(buffer, "FORM", 4))
506                                 type_found = true;
507                         else {
508                                 if(error) *error = "unsupported foreign metadata found, may need newer FLAC decoder (005)";
509                                 return false;
510                         }
511                 }
512                 else if(!type_found) {
513                         FLAC__ASSERT(0);
514                         /* double protection: */
515                         if(error) *error = "unsupported foreign metadata found, may need newer FLAC decoder (006)";
516                         return false;
517                 }
518                 else if(fm->type == FOREIGN_BLOCK_TYPE__RIFF) {
519                         if(!memcmp(buffer, "fmt ", 4)) {
520                                 if(fm->format_block) {
521                                         if(error) *error = "invalid WAVE metadata: multiple \"fmt \" chunks (007)";
522                                         return false;
523                                 }
524                                 if(fm->audio_block) {
525                                         if(error) *error = "invalid WAVE metadata: \"data\" chunk before \"fmt \" chunk (008)";
526                                         return false;
527                                 }
528                                 fm->format_block = fm->num_blocks;
529                         }
530                         else if(!memcmp(buffer, "data", 4)) {
531                                 if(fm->audio_block) {
532                                         if(error) *error = "invalid WAVE metadata: multiple \"data\" chunks (009)";
533                                         return false;
534                                 }
535                                 if(!fm->format_block) {
536                                         if(error) *error = "invalid WAVE metadata: \"data\" chunk before \"fmt \" chunk (010)";
537                                         return false;
538                                 }
539                                 fm->audio_block = fm->num_blocks;
540                         }
541                         else if(fm->is_rf64 && fm->num_blocks == 1) {
542                                 if(memcmp(buffer, "ds64", 4)) {
543                                         if(error) *error = "invalid RF64 metadata: second chunk is not \"ds64\" (011)";
544                                         return false;
545                                 }
546                                 ds64_found = true;
547                         }
548                 }
549                 else if(fm->type == FOREIGN_BLOCK_TYPE__WAVE64) {
550                         if(!memcmp(buffer, "fmt ", 4)) { /* use first 4 bytes instead of whole GUID */
551                                 if(fm->format_block) {
552                                         if(error) *error = "invalid Wave64 metadata: multiple \"fmt \" chunks (012)";
553                                         return false;
554                                 }
555                                 if(fm->audio_block) {
556                                         if(error) *error = "invalid Wave64 metadata: \"data\" chunk before \"fmt \" chunk (013)";
557                                         return false;
558                                 }
559                                 fm->format_block = fm->num_blocks;
560                         }
561                         else if(!memcmp(buffer, "data", 4)) { /* use first 4 bytes instead of whole GUID */
562                                 if(fm->audio_block) {
563                                         if(error) *error = "invalid Wave64 metadata: multiple \"data\" chunks (014)";
564                                         return false;
565                                 }
566                                 if(!fm->format_block) {
567                                         if(error) *error = "invalid Wave64 metadata: \"data\" chunk before \"fmt \" chunk (015)";
568                                         return false;
569                                 }
570                                 fm->audio_block = fm->num_blocks;
571                         }
572                 }
573                 else if(fm->type == FOREIGN_BLOCK_TYPE__AIFF) {
574                         if(!memcmp(buffer, "COMM", 4)) {
575                                 if(fm->format_block) {
576                                         if(error) *error = "invalid AIFF metadata: multiple \"COMM\" chunks (016)";
577                                         return false;
578                                 }
579                                 if(fm->audio_block) {
580                                         if(error) *error = "invalid AIFF metadata: \"SSND\" chunk before \"COMM\" chunk (017)";
581                                         return false;
582                                 }
583                                 fm->format_block = fm->num_blocks;
584                         }
585                         else if(!memcmp(buffer, "SSND", 4)) {
586                                 if(fm->audio_block) {
587                                         if(error) *error = "invalid AIFF metadata: multiple \"SSND\" chunks (018)";
588                                         return false;
589                                 }
590                                 if(!fm->format_block) {
591                                         if(error) *error = "invalid AIFF metadata: \"SSND\" chunk before \"COMM\" chunk (019)";
592                                         return false;
593                                 }
594                                 fm->audio_block = fm->num_blocks;
595                                 /* read SSND offset size */
596                                 if(fread(buffer+4, 1, 8, f) != 8) {
597                                         if(error) *error = "read error (020)";
598                                         return false;
599                                 }
600                                 fm->ssnd_offset_size = unpack32be_(buffer+8);
601                         }
602                 }
603                 else {
604                         FLAC__ASSERT(0);
605                         /* double protection: */
606                         if(error) *error = "unsupported foreign metadata found, may need newer FLAC decoder (021)";
607                         return false;
608                 }
609                 if(!append_block_(fm, offset, FLAC__metadata_simple_iterator_get_block_length(it)-sizeof(id), error))
610                         return false;
611         }
612         if(!type_found) {
613                 if(error) *error = "no foreign metadata found (022)";
614                 return false;
615         }
616         if(fm->is_rf64 && !ds64_found) {
617                 if(error) *error = "invalid RF64 file: second chunk is not \"ds64\" (023)";
618                 return false;
619         }
620         if(!fm->format_block) {
621                 if(error)
622                         *error =
623                                 fm->type==FOREIGN_BLOCK_TYPE__RIFF? "invalid WAVE file: missing \"fmt \" chunk (024)" :
624                                 fm->type==FOREIGN_BLOCK_TYPE__WAVE64? "invalid Wave64 file: missing \"fmt \" chunk (025)" :
625                                 "invalid AIFF file: missing \"COMM\" chunk (026)";
626                 return false;
627         }
628         if(!fm->audio_block) {
629                 if(error)
630                         *error =
631                                 fm->type==FOREIGN_BLOCK_TYPE__RIFF? "invalid WAVE file: missing \"data\" chunk (027)" :
632                                 fm->type==FOREIGN_BLOCK_TYPE__WAVE64? "invalid Wave64 file: missing \"data\" chunk (028)" :
633                                 "invalid AIFF file: missing \"SSND\" chunk (029)";
634                 return false;
635         }
636         return true;
637 }
638
639 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)
640 {
641         size_t i;
642         if(fseeko(fout, offset1, SEEK_SET) < 0) {
643                 if(error) *error = "seek failed in WAVE/AIFF file (002)";
644                 return false;
645         }
646         /* don't write first (RIFF/RF64/FORM) chunk, or ds64 chunk in the case of RF64 */
647         for(i = fm->is_rf64?2:1; i < fm->format_block; i++) {
648                 if(fseeko(fin, fm->blocks[i].offset, SEEK_SET) < 0) {
649                         if(error) *error = "seek failed in FLAC file (003)";
650                         return false;
651                 }
652                 if(!copy_data_(fin, fout, fm->blocks[i].size, error, "read failed in WAVE/AIFF file (004)", "write failed in FLAC file (005)"))
653                         return false;
654         }
655         if(fseeko(fout, offset2, SEEK_SET) < 0) {
656                 if(error) *error = "seek failed in WAVE/AIFF file (006)";
657                 return false;
658         }
659         for(i = fm->format_block+1; i < fm->audio_block; i++) {
660                 if(fseeko(fin, fm->blocks[i].offset, SEEK_SET) < 0) {
661                         if(error) *error = "seek failed in FLAC file (007)";
662                         return false;
663                 }
664                 if(!copy_data_(fin, fout, fm->blocks[i].size, error, "read failed in WAVE/AIFF file (008)", "write failed in FLAC file (009)"))
665                         return false;
666         }
667         if(fseeko(fout, offset3, SEEK_SET) < 0) {
668                 if(error) *error = "seek failed in WAVE/AIFF file (010)";
669                 return false;
670         }
671         for(i = fm->audio_block+1; i < fm->num_blocks; i++) {
672                 if(fseeko(fin, fm->blocks[i].offset, SEEK_SET) < 0) {
673                         if(error) *error = "seek failed in FLAC file (011)";
674                         return false;
675                 }
676                 if(!copy_data_(fin, fout, fm->blocks[i].size, error, "read failed in WAVE/AIFF file (012)", "write failed in FLAC file (013)"))
677                         return false;
678         }
679         return true;
680 }
681
682 foreign_metadata_t *flac__foreign_metadata_new(foreign_block_type_t type)
683 {
684         /* calloc() to zero all the member variables */
685         foreign_metadata_t *x = calloc(sizeof(foreign_metadata_t), 1);
686         if(x) {
687                 x->type = type;
688                 x->is_rf64 = false;
689         }
690         return x;
691 }
692
693 void flac__foreign_metadata_delete(foreign_metadata_t *fm)
694 {
695         if(fm) {
696                 if(fm->blocks)
697                         free(fm->blocks);
698                 free(fm);
699         }
700 }
701
702 FLAC__bool flac__foreign_metadata_read_from_aiff(foreign_metadata_t *fm, const char *filename, const char **error)
703 {
704         FLAC__bool ok;
705         FILE *f = fopen(filename, "rb");
706         if(!f) {
707                 if(error) *error = "can't open AIFF file for reading (000)";
708                 return false;
709         }
710         ok = read_from_aiff_(fm, f, error);
711         fclose(f);
712         return ok;
713 }
714
715 FLAC__bool flac__foreign_metadata_read_from_wave(foreign_metadata_t *fm, const char *filename, const char **error)
716 {
717         FLAC__bool ok;
718         FILE *f = fopen(filename, "rb");
719         if(!f) {
720                 if(error) *error = "can't open WAVE file for reading (000)";
721                 return false;
722         }
723         ok = read_from_wave_(fm, f, error);
724         fclose(f);
725         return ok;
726 }
727
728 FLAC__bool flac__foreign_metadata_read_from_wave64(foreign_metadata_t *fm, const char *filename, const char **error)
729 {
730         FLAC__bool ok;
731         FILE *f = fopen(filename, "rb");
732         if(!f) {
733                 if(error) *error = "can't open Wave64 file for reading (000)";
734                 return false;
735         }
736         ok = read_from_wave64_(fm, f, error);
737         fclose(f);
738         return ok;
739 }
740
741 FLAC__bool flac__foreign_metadata_write_to_flac(foreign_metadata_t *fm, const char *infilename, const char *outfilename, const char **error)
742 {
743         FLAC__bool ok;
744         FILE *fin, *fout;
745         FLAC__Metadata_SimpleIterator *it = FLAC__metadata_simple_iterator_new();
746         if(!it) {
747                 if(error) *error = "out of memory (000)";
748                 return false;
749         }
750         if(!FLAC__metadata_simple_iterator_init(it, outfilename, /*read_only=*/true, /*preserve_file_stats=*/false)) {
751                 if(error) *error = "can't initialize iterator (001)";
752                 FLAC__metadata_simple_iterator_delete(it);
753                 return false;
754         }
755         if(0 == (fin = fopen(infilename, "rb"))) {
756                 if(error) *error = "can't open WAVE/AIFF file for reading (002)";
757                 FLAC__metadata_simple_iterator_delete(it);
758                 return false;
759         }
760         if(0 == (fout = fopen(outfilename, "r+b"))) {
761                 if(error) *error = "can't open FLAC file for updating (003)";
762                 FLAC__metadata_simple_iterator_delete(it);
763                 fclose(fin);
764                 return false;
765         }
766         ok = write_to_flac_(fm, fin, fout, it, error);
767         FLAC__metadata_simple_iterator_delete(it);
768         fclose(fin);
769         fclose(fout);
770         return ok;
771 }
772
773 FLAC__bool flac__foreign_metadata_read_from_flac(foreign_metadata_t *fm, const char *filename, const char **error)
774 {
775         FLAC__bool ok;
776         FILE *f;
777         FLAC__Metadata_SimpleIterator *it = FLAC__metadata_simple_iterator_new();
778         if(!it) {
779                 if(error) *error = "out of memory (000)";
780                 return false;
781         }
782         if(!FLAC__metadata_simple_iterator_init(it, filename, /*read_only=*/true, /*preserve_file_stats=*/false)) {
783                 if(error) *error = "can't initialize iterator (001)";
784                 FLAC__metadata_simple_iterator_delete(it);
785                 return false;
786         }
787         if(0 == (f = fopen(filename, "rb"))) {
788                 if(error) *error = "can't open FLAC file for reading (002)";
789                 FLAC__metadata_simple_iterator_delete(it);
790                 return false;
791         }
792         ok = read_from_flac_(fm, f, it, error);
793         FLAC__metadata_simple_iterator_delete(it);
794         fclose(f);
795         return ok;
796 }
797
798 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)
799 {
800         FLAC__bool ok;
801         FILE *fin, *fout;
802         if(0 == (fin = fopen(infilename, "rb"))) {
803                 if(error) *error = "can't open FLAC file for reading (000)";
804                 return false;
805         }
806         if(0 == (fout = fopen(outfilename, "r+b"))) {
807                 if(error) *error = "can't open WAVE/AIFF file for updating (001)";
808                 fclose(fin);
809                 return false;
810         }
811         ok = write_to_iff_(fm, fin, fout, offset1, offset2, offset3, error);
812         fclose(fin);
813         fclose(fout);
814         return ok;
815 }