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