1 /* flac - Command-line FLAC encoder/decoder
2 * Copyright (C) 2000-2009 Josh Coalson
3 * Copyright (C) 2011-2016 Xiph.Org Foundation
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.
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.
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.
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"
36 #define min(x,y) ((x)<(y)?(x):(y))
39 static const char *FLAC__FOREIGN_METADATA_APPLICATION_ID
[3] = { "aiff" , "riff", "w64 " };
41 static FLAC__uint32
unpack32be_(const FLAC__byte
*b
)
43 return ((FLAC__uint32
)b
[0]<<24) + ((FLAC__uint32
)b
[1]<<16) + ((FLAC__uint32
)b
[2]<<8) + (FLAC__uint32
)b
[3];
46 static FLAC__uint32
unpack32le_(const FLAC__byte
*b
)
48 return (FLAC__uint32
)b
[0] + ((FLAC__uint32
)b
[1]<<8) + ((FLAC__uint32
)b
[2]<<16) + ((FLAC__uint32
)b
[3]<<24);
51 static FLAC__uint64
unpack64le_(const FLAC__byte
*b
)
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);
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
)
59 FLAC__byte buffer
[4096];
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
;
67 if(fwrite(buffer
, 1, need
, fout
) < need
) {
68 if(error
) *error
= write_error
;
76 static FLAC__bool
append_block_(foreign_metadata_t
*fm
, FLAC__off_t offset
, FLAC__uint32 size
, const char **error
)
78 foreign_block_t
*fb
= safe_realloc_muladd2_(fm
->blocks
, sizeof(foreign_block_t
), /*times (*/fm
->num_blocks
, /*+*/1/*)*/);
80 fb
[fm
->num_blocks
].offset
= offset
;
81 fb
[fm
->num_blocks
].size
= size
;
86 if(error
) *error
= "out of memory";
90 static FLAC__bool
read_from_aiff_(foreign_metadata_t
*fm
, FILE *f
, const char **error
)
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)";
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)";
102 if(!append_block_(fm
, offset
, 12, error
))
104 eof_offset
= (FLAC__off_t
)8 + (FLAC__off_t
)unpack32be_(buffer
+4);
107 if((offset
= ftello(f
)) < 0) {
108 if(error
) *error
= "ftello() error (003)";
111 if((size
= fread(buffer
, 1, 8, f
)) < 8) {
112 if(size
== 0 && feof(f
))
114 if(error
) *error
= "invalid AIFF file (004)";
117 size
= unpack32be_(buffer
+4);
118 /* check if pad byte needed */
121 if(!memcmp(buffer
, "COMM", 4)) {
122 if(fm
->format_block
) {
123 if(error
) *error
= "invalid AIFF file: multiple \"COMM\" chunks (005)";
126 if(fm
->audio_block
) {
127 if(error
) *error
= "invalid AIFF file: \"SSND\" chunk before \"COMM\" chunk (006)";
130 fm
->format_block
= fm
->num_blocks
;
132 else if(!memcmp(buffer
, "SSND", 4)) {
133 if(fm
->audio_block
) {
134 if(error
) *error
= "invalid AIFF file: multiple \"SSND\" chunks (007)";
137 if(!fm
->format_block
) {
138 if(error
) *error
= "invalid AIFF file: \"SSND\" chunk before \"COMM\" chunk (008)";
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)";
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)";
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.
158 if(!append_block_(fm
, offset
, 8 + (memcmp(buffer
, "SSND", 4)? size
: 8 + fm
->ssnd_offset_size
), error
))
160 /* skip to next chunk */
161 if(fseeko(f
, size
, SEEK_CUR
) < 0) {
162 if(error
) *error
= "invalid AIFF file: seek error (011)";
166 if(eof_offset
!= ftello(f
)) {
167 if(error
) *error
= "invalid AIFF file: unexpected EOF (012)";
170 if(!fm
->format_block
) {
171 if(error
) *error
= "invalid AIFF file: missing \"COMM\" chunk (013)";
174 if(!fm
->audio_block
) {
175 if(error
) *error
= "invalid AIFF file: missing \"SSND\" chunk (014)";
181 static FLAC__bool
read_from_wave_(foreign_metadata_t
*fm
, FILE *f
, const char **error
)
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)";
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)";
193 if(!memcmp(buffer
, "RF64", 4))
195 if(fm
->is_rf64
&& sizeof(FLAC__off_t
) < 8) {
196 if(error
) *error
= "RF64 is not supported on this compile (r00)";
199 if(!append_block_(fm
, offset
, 12, error
))
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 */
208 if((offset
= ftello(f
)) < 0) {
209 if(error
) *error
= "ftello() error (003)";
212 if((size
= fread(buffer
, 1, 8, f
)) < 8) {
213 if(size
== 0 && feof(f
))
215 if(error
) *error
= "invalid WAVE file (004)";
218 size
= unpack32le_(buffer
+4);
219 /* check if pad byte needed */
222 if(!memcmp(buffer
, "fmt ", 4)) {
223 if(fm
->format_block
) {
224 if(error
) *error
= "invalid WAVE file: multiple \"fmt \" chunks (005)";
227 if(fm
->audio_block
) {
228 if(error
) *error
= "invalid WAVE file: \"data\" chunk before \"fmt \" chunk (006)";
231 fm
->format_block
= fm
->num_blocks
;
233 else if(!memcmp(buffer
, "data", 4)) {
234 if(fm
->audio_block
) {
235 if(error
) *error
= "invalid WAVE file: multiple \"data\" chunks (007)";
238 if(!fm
->format_block
) {
239 if(error
) *error
= "invalid WAVE file: \"data\" chunk before \"fmt \" chunk (008)";
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)";
248 if(!append_block_(fm
, offset
, 8 + (memcmp(buffer
, "data", 4)? size
: 0), error
))
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)";
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)";
263 if(size
> sizeof(buffer2
)) {
264 if(error
) *error
= "RF64 file has \"ds64\" chunk with extra size table, which is not currently supported (r04)";
267 if(fread(buffer2
, 1, sizeof(buffer2
), f
) < sizeof(buffer2
)) {
268 if(error
) *error
= "unexpected EOF reading \"ds64\" chunk data in RF64 file (r05)";
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)";
276 /* check if pad byte needed */
277 if(ds64_data_size
& 1)
279 /* @@@ [2^63 limit] */
280 if(ds64_data_size
< 0) {
281 if(error
) *error
= "RF64 file too large (r09)";
284 if(unpack32le_(buffer2
+24)) {
285 if(error
) *error
= "RF64 file has \"ds64\" chunk with extra size table, which is not currently supported (r06)";
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)";
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)";
303 if(fseeko(f
, size
, SEEK_CUR
) < 0) {
304 if(error
) *error
= "invalid WAVE file: seek error (009)";
310 if(fm
->is_rf64
&& eof_offset
== (FLAC__off_t
)(-1)) {
311 if(error
) *error
= "invalid RF64 file: all RIFF sizes are -1 (r11)";
314 if(eof_offset
!= ftello(f
)) {
315 if(error
) *error
= "invalid WAVE file: unexpected EOF (010)";
318 if(!fm
->format_block
) {
319 if(error
) *error
= "invalid WAVE file: missing \"fmt \" chunk (011)";
322 if(!fm
->audio_block
) {
323 if(error
) *error
= "invalid WAVE file: missing \"data\" chunk (012)";
329 static FLAC__bool
read_from_wave64_(foreign_metadata_t
*fm
, FILE *f
, const char **error
)
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)";
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)
344 if(error
) *error
= "unsupported Wave64 layout (002)";
347 if(sizeof(FLAC__off_t
) < 8) {
348 if(error
) *error
= "Wave64 is not supported on this compile (r00)";
351 if(!append_block_(fm
, offset
, 40, error
))
353 eof_offset
= (FLAC__off_t
)unpack64le_(buffer
+16); /*@@@ [2^63 limit] */
356 if((offset
= ftello(f
)) < 0) {
357 if(error
) *error
= "ftello() error (003)";
360 if((size
= fread(buffer
, 1, 24, f
)) < 24) {
361 if(size
== 0 && feof(f
))
363 if(error
) *error
= "invalid Wave64 file (004)";
366 size
= unpack64le_(buffer
+16);
367 /* check if pad bytes needed */
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)";
376 if(fm
->audio_block
) {
377 if(error
) *error
= "invalid Wave64 file: \"data\" chunk before \"fmt \" chunk (006)";
380 fm
->format_block
= fm
->num_blocks
;
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)";
388 if(!fm
->format_block
) {
389 if(error
) *error
= "invalid Wave64 file: \"data\" chunk before \"fmt \" chunk (008)";
392 fm
->audio_block
= fm
->num_blocks
;
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
))
396 /* skip to next chunk */
397 if(fseeko(f
, size
-24, SEEK_CUR
) < 0) {
398 if(error
) *error
= "invalid Wave64 file: seek error (009)";
402 if(eof_offset
!= ftello(f
)) {
403 if(error
) *error
= "invalid Wave64 file: unexpected EOF (010)";
406 if(!fm
->format_block
) {
407 if(error
) *error
= "invalid Wave64 file: missing \"fmt \" chunk (011)";
410 if(!fm
->audio_block
) {
411 if(error
) *error
= "invalid Wave64 file: missing \"data\" chunk (012)";
417 static FLAC__bool
write_to_flac_(foreign_metadata_t
*fm
, FILE *fin
, FILE *fout
, FLAC__Metadata_SimpleIterator
*it
, const char **error
)
419 FLAC__byte buffer
[4];
420 const uint32_t 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 */
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)";
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)";
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)";
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)";
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)";
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)";
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)";
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)"))
473 static FLAC__bool
read_from_flac_(foreign_metadata_t
*fm
, FILE *f
, FLAC__Metadata_SimpleIterator
*it
, const char **error
)
475 FLAC__byte id
[4], buffer
[12];
477 FLAC__bool type_found
= false, ds64_found
= false;
479 FLAC__ASSERT(FLAC__STREAM_METADATA_APPLICATION_ID_LEN
== sizeof(id
)*8);
481 while(FLAC__metadata_simple_iterator_next(it
)) {
482 if(FLAC__metadata_simple_iterator_get_block_type(it
) != FLAC__METADATA_TYPE_APPLICATION
)
484 if(!FLAC__metadata_simple_iterator_get_application_id(it
, id
)) {
485 if(error
) *error
= "FLAC__metadata_simple_iterator_get_application_id() error (002)";
488 if(memcmp(id
, FLAC__FOREIGN_METADATA_APPLICATION_ID
[fm
->type
], sizeof(id
)))
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)";
499 if(fread(buffer
, 1, 4, f
) != 4) {
500 if(error
) *error
= "read error (004)";
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
))
507 else if(fm
->type
== FOREIGN_BLOCK_TYPE__WAVE64
&& 0 == memcmp(buffer
, "riff", 4)) /* use first 4 bytes instead of whole GUID */
509 else if(fm
->type
== FOREIGN_BLOCK_TYPE__AIFF
&& 0 == memcmp(buffer
, "FORM", 4))
512 if(error
) *error
= "unsupported foreign metadata found, may need newer FLAC decoder (005)";
516 else if(!type_found
) {
518 /* double protection: */
519 if(error
) *error
= "unsupported foreign metadata found, may need newer FLAC decoder (006)";
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)";
528 if(fm
->audio_block
) {
529 if(error
) *error
= "invalid WAVE metadata: \"data\" chunk before \"fmt \" chunk (008)";
532 fm
->format_block
= fm
->num_blocks
;
534 else if(!memcmp(buffer
, "data", 4)) {
535 if(fm
->audio_block
) {
536 if(error
) *error
= "invalid WAVE metadata: multiple \"data\" chunks (009)";
539 if(!fm
->format_block
) {
540 if(error
) *error
= "invalid WAVE metadata: \"data\" chunk before \"fmt \" chunk (010)";
543 fm
->audio_block
= fm
->num_blocks
;
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)";
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)";
559 if(fm
->audio_block
) {
560 if(error
) *error
= "invalid Wave64 metadata: \"data\" chunk before \"fmt \" chunk (013)";
563 fm
->format_block
= fm
->num_blocks
;
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)";
570 if(!fm
->format_block
) {
571 if(error
) *error
= "invalid Wave64 metadata: \"data\" chunk before \"fmt \" chunk (015)";
574 fm
->audio_block
= fm
->num_blocks
;
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)";
583 if(fm
->audio_block
) {
584 if(error
) *error
= "invalid AIFF metadata: \"SSND\" chunk before \"COMM\" chunk (017)";
587 fm
->format_block
= fm
->num_blocks
;
589 else if(!memcmp(buffer
, "SSND", 4)) {
590 if(fm
->audio_block
) {
591 if(error
) *error
= "invalid AIFF metadata: multiple \"SSND\" chunks (018)";
594 if(!fm
->format_block
) {
595 if(error
) *error
= "invalid AIFF metadata: \"SSND\" chunk before \"COMM\" chunk (019)";
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)";
604 fm
->ssnd_offset_size
= unpack32be_(buffer
+8);
609 /* double protection: */
610 if(error
) *error
= "unsupported foreign metadata found, may need newer FLAC decoder (021)";
613 if(!append_block_(fm
, offset
, FLAC__metadata_simple_iterator_get_block_length(it
)-sizeof(id
), error
))
617 if(error
) *error
= "no foreign metadata found (022)";
620 if(fm
->is_rf64
&& !ds64_found
) {
621 if(error
) *error
= "invalid RF64 file: second chunk is not \"ds64\" (023)";
624 if(!fm
->format_block
) {
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)";
632 if(!fm
->audio_block
) {
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)";
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
)
646 if(fseeko(fout
, offset1
, SEEK_SET
) < 0) {
647 if(error
) *error
= "seek failed in WAVE/AIFF file (002)";
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)";
656 if(!copy_data_(fin
, fout
, fm
->blocks
[i
].size
, error
, "read failed in WAVE/AIFF file (004)", "write failed in FLAC file (005)"))
659 if(fseeko(fout
, offset2
, SEEK_SET
) < 0) {
660 if(error
) *error
= "seek failed in WAVE/AIFF file (006)";
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)";
668 if(!copy_data_(fin
, fout
, fm
->blocks
[i
].size
, error
, "read failed in WAVE/AIFF file (008)", "write failed in FLAC file (009)"))
671 if(fseeko(fout
, offset3
, SEEK_SET
) < 0) {
672 if(error
) *error
= "seek failed in WAVE/AIFF file (010)";
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)";
680 if(!copy_data_(fin
, fout
, fm
->blocks
[i
].size
, error
, "read failed in WAVE/AIFF file (012)", "write failed in FLAC file (013)"))
686 foreign_metadata_t
*flac__foreign_metadata_new(foreign_block_type_t type
)
688 /* calloc() to zero all the member variables */
689 foreign_metadata_t
*x
= calloc(sizeof(foreign_metadata_t
), 1);
697 void flac__foreign_metadata_delete(foreign_metadata_t
*fm
)
706 FLAC__bool
flac__foreign_metadata_read_from_aiff(foreign_metadata_t
*fm
, const char *filename
, const char **error
)
709 FILE *f
= flac_fopen(filename
, "rb");
711 if(error
) *error
= "can't open AIFF file for reading (000)";
714 ok
= read_from_aiff_(fm
, f
, error
);
719 FLAC__bool
flac__foreign_metadata_read_from_wave(foreign_metadata_t
*fm
, const char *filename
, const char **error
)
722 FILE *f
= flac_fopen(filename
, "rb");
724 if(error
) *error
= "can't open WAVE file for reading (000)";
727 ok
= read_from_wave_(fm
, f
, error
);
732 FLAC__bool
flac__foreign_metadata_read_from_wave64(foreign_metadata_t
*fm
, const char *filename
, const char **error
)
735 FILE *f
= flac_fopen(filename
, "rb");
737 if(error
) *error
= "can't open Wave64 file for reading (000)";
740 ok
= read_from_wave64_(fm
, f
, error
);
745 FLAC__bool
flac__foreign_metadata_write_to_flac(foreign_metadata_t
*fm
, const char *infilename
, const char *outfilename
, const char **error
)
749 FLAC__Metadata_SimpleIterator
*it
= FLAC__metadata_simple_iterator_new();
751 if(error
) *error
= "out of memory (000)";
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
);
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
);
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
);
770 ok
= write_to_flac_(fm
, fin
, fout
, it
, error
);
771 FLAC__metadata_simple_iterator_delete(it
);
777 FLAC__bool
flac__foreign_metadata_read_from_flac(foreign_metadata_t
*fm
, const char *filename
, const char **error
)
781 FLAC__Metadata_SimpleIterator
*it
= FLAC__metadata_simple_iterator_new();
783 if(error
) *error
= "out of memory (000)";
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
);
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
);
796 ok
= read_from_flac_(fm
, f
, it
, error
);
797 FLAC__metadata_simple_iterator_delete(it
);
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
)
806 if(0 == (fin
= flac_fopen(infilename
, "rb"))) {
807 if(error
) *error
= "can't open FLAC file for reading (000)";
810 if(0 == (fout
= flac_fopen(outfilename
, "r+b"))) {
811 if(error
) *error
= "can't open WAVE/AIFF file for updating (001)";
815 ok
= write_to_iff_(fm
, fin
, fout
, offset1
, offset2
, offset3
, error
);