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