1 /* flac - Command-line FLAC encoder/decoder
2 * Copyright (C) 2000,2001,2002,2003,2004,2005,2006,2007,2008,2009 Josh Coalson
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.
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.
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.
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"
35 #define min(x,y) ((x)<(y)?(x):(y))
38 static const char *FLAC__FOREIGN_METADATA_APPLICATION_ID
[3] = { "aiff" , "riff", "w64 " };
40 static FLAC__uint32
unpack32be_(const FLAC__byte
*b
)
42 return ((FLAC__uint32
)b
[0]<<24) + ((FLAC__uint32
)b
[1]<<16) + ((FLAC__uint32
)b
[2]<<8) + (FLAC__uint32
)b
[3];
45 static FLAC__uint32
unpack32le_(const FLAC__byte
*b
)
47 return (FLAC__uint32
)b
[0] + ((FLAC__uint32
)b
[1]<<8) + ((FLAC__uint32
)b
[2]<<16) + ((FLAC__uint32
)b
[3]<<24);
50 static FLAC__uint64
unpack64le_(const FLAC__byte
*b
)
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);
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
)
58 FLAC__byte buffer
[4096];
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
;
66 if(fwrite(buffer
, 1, need
, fout
) < need
) {
67 if(error
) *error
= write_error
;
75 static FLAC__bool
append_block_(foreign_metadata_t
*fm
, FLAC__off_t offset
, FLAC__uint32 size
, const char **error
)
77 foreign_block_t
*fb
= safe_realloc_muladd2_(fm
->blocks
, sizeof(foreign_block_t
), /*times (*/fm
->num_blocks
, /*+*/1/*)*/);
79 fb
[fm
->num_blocks
].offset
= offset
;
80 fb
[fm
->num_blocks
].size
= size
;
85 if(error
) *error
= "out of memory";
89 static FLAC__bool
read_from_aiff_(foreign_metadata_t
*fm
, FILE *f
, const char **error
)
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)";
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)";
101 if(!append_block_(fm
, offset
, 12, error
))
103 eof_offset
= (FLAC__off_t
)8 + (FLAC__off_t
)unpack32be_(buffer
+4);
106 if((offset
= ftello(f
)) < 0) {
107 if(error
) *error
= "ftello() error (003)";
110 if((size
= fread(buffer
, 1, 8, f
)) < 8) {
111 if(size
== 0 && feof(f
))
113 if(error
) *error
= "invalid AIFF file (004)";
116 size
= unpack32be_(buffer
+4);
117 /* check if pad byte needed */
120 if(!memcmp(buffer
, "COMM", 4)) {
121 if(fm
->format_block
) {
122 if(error
) *error
= "invalid AIFF file: multiple \"COMM\" chunks (005)";
125 if(fm
->audio_block
) {
126 if(error
) *error
= "invalid AIFF file: \"SSND\" chunk before \"COMM\" chunk (006)";
129 fm
->format_block
= fm
->num_blocks
;
131 else if(!memcmp(buffer
, "SSND", 4)) {
132 if(fm
->audio_block
) {
133 if(error
) *error
= "invalid AIFF file: multiple \"SSND\" chunks (007)";
136 if(!fm
->format_block
) {
137 if(error
) *error
= "invalid AIFF file: \"SSND\" chunk before \"COMM\" chunk (008)";
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)";
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)";
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.
157 if(!append_block_(fm
, offset
, 8 + (memcmp(buffer
, "SSND", 4)? size
: 8 + fm
->ssnd_offset_size
), error
))
159 /* skip to next chunk */
160 if(fseeko(f
, size
, SEEK_CUR
) < 0) {
161 if(error
) *error
= "invalid AIFF file: seek error (011)";
165 if(eof_offset
!= ftello(f
)) {
166 if(error
) *error
= "invalid AIFF file: unexpected EOF (012)";
169 if(!fm
->format_block
) {
170 if(error
) *error
= "invalid AIFF file: missing \"COMM\" chunk (013)";
173 if(!fm
->audio_block
) {
174 if(error
) *error
= "invalid AIFF file: missing \"SSND\" chunk (014)";
180 static FLAC__bool
read_from_wave_(foreign_metadata_t
*fm
, FILE *f
, const char **error
)
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)";
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)";
192 if(!memcmp(buffer
, "RF64", 4))
194 if(fm
->is_rf64
&& sizeof(FLAC__off_t
) < 8) {
195 if(error
) *error
= "RF64 is not supported on this compile (r00)";
198 if(!append_block_(fm
, offset
, 12, error
))
200 if(!fm
->is_rf64
|| unpack32le_(buffer
+4) != 0xffffffffu
)
201 eof_offset
= (FLAC__off_t
)8 + (FLAC__off_t
)unpack32le_(buffer
+4);
204 if((offset
= ftello(f
)) < 0) {
205 if(error
) *error
= "ftello() error (003)";
208 if((size
= fread(buffer
, 1, 8, f
)) < 8) {
209 if(size
== 0 && feof(f
))
211 if(error
) *error
= "invalid WAVE file (004)";
214 size
= unpack32le_(buffer
+4);
215 /* check if pad byte needed */
218 if(!memcmp(buffer
, "fmt ", 4)) {
219 if(fm
->format_block
) {
220 if(error
) *error
= "invalid WAVE file: multiple \"fmt \" chunks (005)";
223 if(fm
->audio_block
) {
224 if(error
) *error
= "invalid WAVE file: \"data\" chunk before \"fmt \" chunk (006)";
227 fm
->format_block
= fm
->num_blocks
;
229 else if(!memcmp(buffer
, "data", 4)) {
230 if(fm
->audio_block
) {
231 if(error
) *error
= "invalid WAVE file: multiple \"data\" chunks (007)";
234 if(!fm
->format_block
) {
235 if(error
) *error
= "invalid WAVE file: \"data\" chunk before \"fmt \" chunk (008)";
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)";
244 if(!append_block_(fm
, offset
, 8 + (memcmp(buffer
, "data", 4)? size
: 0), error
))
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)";
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)";
259 if(size
> sizeof(buffer2
)) {
260 if(error
) *error
= "RF64 file has \"ds64\" chunk with extra size table, which is not currently supported (r04)";
263 if(fread(buffer2
, 1, sizeof(buffer2
), f
) < sizeof(buffer2
)) {
264 if(error
) *error
= "unexpected EOF reading \"ds64\" chunk data in RF64 file (r05)";
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)";
272 /* check if pad byte needed */
273 if(ds64_data_size
& 1)
275 /* @@@ [2^63 limit] */
276 if(ds64_data_size
< 0) {
277 if(error
) *error
= "RF64 file too large (r09)";
280 if(unpack32le_(buffer2
+24)) {
281 if(error
) *error
= "RF64 file has \"ds64\" chunk with extra size table, which is not currently supported (r06)";
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)";
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)";
299 if(fseeko(f
, size
, SEEK_CUR
) < 0) {
300 if(error
) *error
= "invalid WAVE file: seek error (009)";
306 if(fm
->is_rf64
&& eof_offset
== (FLAC__off_t
)(-1)) {
307 if(error
) *error
= "invalid RF64 file: all RIFF sizes are -1 (r11)";
310 if(eof_offset
!= ftello(f
)) {
311 if(error
) *error
= "invalid WAVE file: unexpected EOF (010)";
314 if(!fm
->format_block
) {
315 if(error
) *error
= "invalid WAVE file: missing \"fmt \" chunk (011)";
318 if(!fm
->audio_block
) {
319 if(error
) *error
= "invalid WAVE file: missing \"data\" chunk (012)";
325 static FLAC__bool
read_from_wave64_(foreign_metadata_t
*fm
, FILE *f
, const char **error
)
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)";
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\xD6\xA5\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\xD1\x8C\x00\xC0\x4F\x8E\xDB\x8A", 16)
340 if(error
) *error
= "unsupported Wave64 layout (002)";
343 if(sizeof(FLAC__off_t
) < 8) {
344 if(error
) *error
= "Wave64 is not supported on this compile (r00)";
347 if(!append_block_(fm
, offset
, 40, error
))
349 eof_offset
= (FLAC__off_t
)unpack64le_(buffer
+16); /*@@@ [2^63 limit] */
352 if((offset
= ftello(f
)) < 0) {
353 if(error
) *error
= "ftello() error (003)";
356 if((size
= fread(buffer
, 1, 24, f
)) < 24) {
357 if(size
== 0 && feof(f
))
359 if(error
) *error
= "invalid Wave64 file (004)";
362 size
= unpack64le_(buffer
+16);
363 /* check if pad bytes needed */
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\xD1\x8C\x00\xC0\x4F\x8E\xDB\x8A", 16)) {
368 if(fm
->format_block
) {
369 if(error
) *error
= "invalid Wave64 file: multiple \"fmt \" chunks (005)";
372 if(fm
->audio_block
) {
373 if(error
) *error
= "invalid Wave64 file: \"data\" chunk before \"fmt \" chunk (006)";
376 fm
->format_block
= fm
->num_blocks
;
378 /* data GUID 61746164-ACF3-11D3-8CD1-00C04F8EDB8A */
379 else if(!memcmp(buffer
, "\x64\x61\x74\x61\xF3\xAC\xD3\x11\xD1\x8C\x00\xC0\x4F\x8E\xDB\x8A", 16)) {
380 if(fm
->audio_block
) {
381 if(error
) *error
= "invalid Wave64 file: multiple \"data\" chunks (007)";
384 if(!fm
->format_block
) {
385 if(error
) *error
= "invalid Wave64 file: \"data\" chunk before \"fmt \" chunk (008)";
388 fm
->audio_block
= fm
->num_blocks
;
390 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
))
392 /* skip to next chunk */
393 if(fseeko(f
, size
-24, SEEK_CUR
) < 0) {
394 if(error
) *error
= "invalid Wave64 file: seek error (009)";
398 if(eof_offset
!= ftello(f
)) {
399 if(error
) *error
= "invalid Wave64 file: unexpected EOF (010)";
402 if(!fm
->format_block
) {
403 if(error
) *error
= "invalid Wave64 file: missing \"fmt \" chunk (011)";
406 if(!fm
->audio_block
) {
407 if(error
) *error
= "invalid Wave64 file: missing \"data\" chunk (012)";
413 static FLAC__bool
write_to_flac_(foreign_metadata_t
*fm
, FILE *fin
, FILE *fout
, FLAC__Metadata_SimpleIterator
*it
, const char **error
)
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 */
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)";
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)";
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)";
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)";
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)";
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)";
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)";
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)"))
469 static FLAC__bool
read_from_flac_(foreign_metadata_t
*fm
, FILE *f
, FLAC__Metadata_SimpleIterator
*it
, const char **error
)
471 FLAC__byte id
[4], buffer
[12];
473 FLAC__bool type_found
= false, ds64_found
= false;
475 FLAC__ASSERT(FLAC__STREAM_METADATA_APPLICATION_ID_LEN
== sizeof(id
)*8);
477 while(FLAC__metadata_simple_iterator_next(it
)) {
478 if(FLAC__metadata_simple_iterator_get_block_type(it
) != FLAC__METADATA_TYPE_APPLICATION
)
480 if(!FLAC__metadata_simple_iterator_get_application_id(it
, id
)) {
481 if(error
) *error
= "FLAC__metadata_simple_iterator_get_application_id() error (002)";
484 if(memcmp(id
, FLAC__FOREIGN_METADATA_APPLICATION_ID
[fm
->type
], sizeof(id
)))
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)";
495 if(fread(buffer
, 1, 4, f
) != 4) {
496 if(error
) *error
= "read error (004)";
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
))
503 else if(fm
->type
== FOREIGN_BLOCK_TYPE__WAVE64
&& 0 == memcmp(buffer
, "riff", 4)) /* use first 4 bytes instead of whole GUID */
505 else if(fm
->type
== FOREIGN_BLOCK_TYPE__AIFF
&& 0 == memcmp(buffer
, "FORM", 4))
508 if(error
) *error
= "unsupported foreign metadata found, may need newer FLAC decoder (005)";
512 else if(!type_found
) {
514 /* double protection: */
515 if(error
) *error
= "unsupported foreign metadata found, may need newer FLAC decoder (006)";
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)";
524 if(fm
->audio_block
) {
525 if(error
) *error
= "invalid WAVE metadata: \"data\" chunk before \"fmt \" chunk (008)";
528 fm
->format_block
= fm
->num_blocks
;
530 else if(!memcmp(buffer
, "data", 4)) {
531 if(fm
->audio_block
) {
532 if(error
) *error
= "invalid WAVE metadata: multiple \"data\" chunks (009)";
535 if(!fm
->format_block
) {
536 if(error
) *error
= "invalid WAVE metadata: \"data\" chunk before \"fmt \" chunk (010)";
539 fm
->audio_block
= fm
->num_blocks
;
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)";
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)";
555 if(fm
->audio_block
) {
556 if(error
) *error
= "invalid Wave64 metadata: \"data\" chunk before \"fmt \" chunk (013)";
559 fm
->format_block
= fm
->num_blocks
;
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)";
566 if(!fm
->format_block
) {
567 if(error
) *error
= "invalid Wave64 metadata: \"data\" chunk before \"fmt \" chunk (015)";
570 fm
->audio_block
= fm
->num_blocks
;
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)";
579 if(fm
->audio_block
) {
580 if(error
) *error
= "invalid AIFF metadata: \"SSND\" chunk before \"COMM\" chunk (017)";
583 fm
->format_block
= fm
->num_blocks
;
585 else if(!memcmp(buffer
, "SSND", 4)) {
586 if(fm
->audio_block
) {
587 if(error
) *error
= "invalid AIFF metadata: multiple \"SSND\" chunks (018)";
590 if(!fm
->format_block
) {
591 if(error
) *error
= "invalid AIFF metadata: \"SSND\" chunk before \"COMM\" chunk (019)";
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)";
600 fm
->ssnd_offset_size
= unpack32be_(buffer
+8);
605 /* double protection: */
606 if(error
) *error
= "unsupported foreign metadata found, may need newer FLAC decoder (021)";
609 if(!append_block_(fm
, offset
, FLAC__metadata_simple_iterator_get_block_length(it
)-sizeof(id
), error
))
613 if(error
) *error
= "no foreign metadata found (022)";
616 if(fm
->is_rf64
&& !ds64_found
) {
617 if(error
) *error
= "invalid RF64 file: second chunk is not \"ds64\" (023)";
620 if(!fm
->format_block
) {
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)";
628 if(!fm
->audio_block
) {
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)";
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
)
642 if(fseeko(fout
, offset1
, SEEK_SET
) < 0) {
643 if(error
) *error
= "seek failed in WAVE/AIFF file (002)";
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)";
652 if(!copy_data_(fin
, fout
, fm
->blocks
[i
].size
, error
, "read failed in WAVE/AIFF file (004)", "write failed in FLAC file (005)"))
655 if(fseeko(fout
, offset2
, SEEK_SET
) < 0) {
656 if(error
) *error
= "seek failed in WAVE/AIFF file (006)";
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)";
664 if(!copy_data_(fin
, fout
, fm
->blocks
[i
].size
, error
, "read failed in WAVE/AIFF file (008)", "write failed in FLAC file (009)"))
667 if(fseeko(fout
, offset3
, SEEK_SET
) < 0) {
668 if(error
) *error
= "seek failed in WAVE/AIFF file (010)";
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)";
676 if(!copy_data_(fin
, fout
, fm
->blocks
[i
].size
, error
, "read failed in WAVE/AIFF file (012)", "write failed in FLAC file (013)"))
682 foreign_metadata_t
*flac__foreign_metadata_new(foreign_block_type_t type
)
684 /* calloc() to zero all the member variables */
685 foreign_metadata_t
*x
= calloc(sizeof(foreign_metadata_t
), 1);
693 void flac__foreign_metadata_delete(foreign_metadata_t
*fm
)
702 FLAC__bool
flac__foreign_metadata_read_from_aiff(foreign_metadata_t
*fm
, const char *filename
, const char **error
)
705 FILE *f
= fopen(filename
, "rb");
707 if(error
) *error
= "can't open AIFF file for reading (000)";
710 ok
= read_from_aiff_(fm
, f
, error
);
715 FLAC__bool
flac__foreign_metadata_read_from_wave(foreign_metadata_t
*fm
, const char *filename
, const char **error
)
718 FILE *f
= fopen(filename
, "rb");
720 if(error
) *error
= "can't open WAVE file for reading (000)";
723 ok
= read_from_wave_(fm
, f
, error
);
728 FLAC__bool
flac__foreign_metadata_read_from_wave64(foreign_metadata_t
*fm
, const char *filename
, const char **error
)
731 FILE *f
= fopen(filename
, "rb");
733 if(error
) *error
= "can't open Wave64 file for reading (000)";
736 ok
= read_from_wave64_(fm
, f
, error
);
741 FLAC__bool
flac__foreign_metadata_write_to_flac(foreign_metadata_t
*fm
, const char *infilename
, const char *outfilename
, const char **error
)
745 FLAC__Metadata_SimpleIterator
*it
= FLAC__metadata_simple_iterator_new();
747 if(error
) *error
= "out of memory (000)";
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
);
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
);
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
);
766 ok
= write_to_flac_(fm
, fin
, fout
, it
, error
);
767 FLAC__metadata_simple_iterator_delete(it
);
773 FLAC__bool
flac__foreign_metadata_read_from_flac(foreign_metadata_t
*fm
, const char *filename
, const char **error
)
777 FLAC__Metadata_SimpleIterator
*it
= FLAC__metadata_simple_iterator_new();
779 if(error
) *error
= "out of memory (000)";
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
);
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
);
792 ok
= read_from_flac_(fm
, f
, it
, error
);
793 FLAC__metadata_simple_iterator_delete(it
);
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
)
802 if(0 == (fin
= fopen(infilename
, "rb"))) {
803 if(error
) *error
= "can't open FLAC file for reading (000)";
806 if(0 == (fout
= fopen(outfilename
, "r+b"))) {
807 if(error
) *error
= "can't open WAVE/AIFF file for updating (001)";
811 ok
= write_to_iff_(fm
, fin
, fout
, offset1
, offset2
, offset3
, error
);