Fix a couple of Windows 2Gig file size issues.
[flac.git] / src / flac / foreign_metadata.c
blobb8e8b4655a60da620248667de3f0055b49144fa5
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.
19 #if HAVE_CONFIG_H
20 # include <config.h>
21 #endif
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"
32 #ifdef min
33 #undef min
34 #endif
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];
59 size_t left;
60 for(left = size; left > 0; ) {
61 size_t need = min(sizeof(buffer), left);
62 if(fread(buffer, 1, need, fin) < need) {
63 if(error) *error = read_error;
64 return false;
66 if(fwrite(buffer, 1, need, fout) < need) {
67 if(error) *error = write_error;
68 return false;
70 left -= need;
72 return true;
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/*)*/);
78 if(fb) {
79 fb[fm->num_blocks].offset = offset;
80 fb[fm->num_blocks].size = size;
81 fm->num_blocks++;
82 fm->blocks = fb;
83 return true;
85 if(error) *error = "out of memory";
86 return false;
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)";
95 return false;
97 if(fread(buffer, 1, 12, f) < 12 || memcmp(buffer, "FORM", 4) || (memcmp(buffer+8, "AIFF", 4) && memcmp(buffer+8, "AIFC", 4))) {
98 if(error) *error = "unsupported FORM layout (002)";
99 return false;
101 if(!append_block_(fm, offset, 12, error))
102 return false;
103 eof_offset = (FLAC__off_t)8 + (FLAC__off_t)unpack32be_(buffer+4);
104 while(!feof(f)) {
105 FLAC__uint32 size;
106 if((offset = ftello(f)) < 0) {
107 if(error) *error = "ftello() error (003)";
108 return false;
110 if((size = fread(buffer, 1, 8, f)) < 8) {
111 if(size == 0 && feof(f))
112 break;
113 if(error) *error = "invalid AIFF file (004)";
114 return false;
116 size = unpack32be_(buffer+4);
117 /* check if pad byte needed */
118 if(size & 1)
119 size++;
120 if(!memcmp(buffer, "COMM", 4)) {
121 if(fm->format_block) {
122 if(error) *error = "invalid AIFF file: multiple \"COMM\" chunks (005)";
123 return false;
125 if(fm->audio_block) {
126 if(error) *error = "invalid AIFF file: \"SSND\" chunk before \"COMM\" chunk (006)";
127 return false;
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)";
134 return false;
136 if(!fm->format_block) {
137 if(error) *error = "invalid AIFF file: \"SSND\" chunk before \"COMM\" chunk (008)";
138 return false;
140 fm->audio_block = fm->num_blocks;
141 /* read #offset bytes */
142 if(fread(buffer+8, 1, 4, f) < 4) {
143 if(error) *error = "invalid AIFF file (009)";
144 return false;
146 fm->ssnd_offset_size = unpack32be_(buffer+8);
147 if(fseeko(f, -4, SEEK_CUR) < 0) {
148 if(error) *error = "invalid AIFF file: seek error (010)";
149 return false;
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))
158 return false;
159 /* skip to next chunk */
160 if(fseeko(f, size, SEEK_CUR) < 0) {
161 if(error) *error = "invalid AIFF file: seek error (011)";
162 return false;
165 if(eof_offset != ftello(f)) {
166 if(error) *error = "invalid AIFF file: unexpected EOF (012)";
167 return false;
169 if(!fm->format_block) {
170 if(error) *error = "invalid AIFF file: missing \"COMM\" chunk (013)";
171 return false;
173 if(!fm->audio_block) {
174 if(error) *error = "invalid AIFF file: missing \"SSND\" chunk (014)";
175 return false;
177 return true;
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)";
186 return false;
188 if(fread(buffer, 1, 12, f) < 12 || (memcmp(buffer, "RIFF", 4) && memcmp(buffer, "RF64", 4)) || memcmp(buffer+8, "WAVE", 4)) {
189 if(error) *error = "unsupported RIFF layout (002)";
190 return false;
192 if(!memcmp(buffer, "RF64", 4))
193 fm->is_rf64 = true;
194 if(fm->is_rf64 && sizeof(FLAC__off_t) < 8) {
195 if(error) *error = "RF64 is not supported on this compile (r00)";
196 return false;
198 if(!append_block_(fm, offset, 12, error))
199 return false;
200 if(!fm->is_rf64 || unpack32le_(buffer+4) != 0xffffffffu)
201 eof_offset = (FLAC__off_t)8 + (FLAC__off_t)unpack32le_(buffer+4);
202 while(!feof(f)) {
203 FLAC__uint32 size;
204 if((offset = ftello(f)) < 0) {
205 if(error) *error = "ftello() error (003)";
206 return false;
208 if((size = fread(buffer, 1, 8, f)) < 8) {
209 if(size == 0 && feof(f))
210 break;
211 if(error) *error = "invalid WAVE file (004)";
212 return false;
214 size = unpack32le_(buffer+4);
215 /* check if pad byte needed */
216 if(size & 1)
217 size++;
218 if(!memcmp(buffer, "fmt ", 4)) {
219 if(fm->format_block) {
220 if(error) *error = "invalid WAVE file: multiple \"fmt \" chunks (005)";
221 return false;
223 if(fm->audio_block) {
224 if(error) *error = "invalid WAVE file: \"data\" chunk before \"fmt \" chunk (006)";
225 return false;
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)";
232 return false;
234 if(!fm->format_block) {
235 if(error) *error = "invalid WAVE file: \"data\" chunk before \"fmt \" chunk (008)";
236 return false;
238 fm->audio_block = fm->num_blocks;
239 if(fm->is_rf64 && fm->num_blocks < 2) {
240 if(error) *error = "invalid RF64 file: \"data\" chunk before \"ds64\" chunk (r01)";
241 return false;
244 if(!append_block_(fm, offset, 8 + (memcmp(buffer, "data", 4)? size : 0), error))
245 return false;
246 /* parse ds64 chunk if necessary */
247 if(fm->is_rf64 && fm->num_blocks == 2) {
248 FLAC__byte buffer2[7*4];
249 if(memcmp(buffer, "ds64", 4)) {
250 if(error) *error = "invalid RF64 file: \"ds64\" chunk does not immediately follow \"WAVE\" marker (r02)";
251 return false;
253 /* unpack the size again since we don't want the padding byte effect */
254 size = unpack32le_(buffer+4);
255 if(size < sizeof(buffer2)) {
256 if(error) *error = "invalid RF64 file: \"ds64\" chunk size is < 28 (r03)";
257 return false;
259 if(size > sizeof(buffer2)) {
260 if(error) *error = "RF64 file has \"ds64\" chunk with extra size table, which is not currently supported (r04)";
261 return false;
263 if(fread(buffer2, 1, sizeof(buffer2), f) < sizeof(buffer2)) {
264 if(error) *error = "unexpected EOF reading \"ds64\" chunk data in RF64 file (r05)";
265 return false;
267 ds64_data_size = (FLAC__off_t)unpack64le_(buffer2+8);
268 if(ds64_data_size == (FLAC__off_t)(-1)) {
269 if(error) *error = "RF64 file has \"ds64\" chunk with data size == -1 (r08)";
270 return false;
272 /* check if pad byte needed */
273 if(ds64_data_size & 1)
274 ds64_data_size++;
275 /* @@@ [2^63 limit] */
276 if(ds64_data_size < 0) {
277 if(error) *error = "RF64 file too large (r09)";
278 return false;
280 if(unpack32le_(buffer2+24)) {
281 if(error) *error = "RF64 file has \"ds64\" chunk with extra size table, which is not currently supported (r06)";
282 return false;
284 eof_offset = (FLAC__off_t)8 + (FLAC__off_t)unpack64le_(buffer2);
285 /* @@@ [2^63 limit] */
286 if((FLAC__off_t)unpack64le_(buffer2) < 0 || eof_offset < 0) {
287 if(error) *error = "RF64 file too large (r07)";
288 return false;
291 else { /* skip to next chunk */
292 if(fm->is_rf64 && !memcmp(buffer, "data", 4) && unpack32le_(buffer+4) == 0xffffffffu) {
293 if(fseeko(f, ds64_data_size, SEEK_CUR) < 0) {
294 if(error) *error = "invalid RF64 file: seek error (r10)";
295 return false;
298 else {
299 if(fseeko(f, size, SEEK_CUR) < 0) {
300 if(error) *error = "invalid WAVE file: seek error (009)";
301 return false;
306 if(fm->is_rf64 && eof_offset == (FLAC__off_t)(-1)) {
307 if(error) *error = "invalid RF64 file: all RIFF sizes are -1 (r11)";
308 return false;
310 if(eof_offset != ftello(f)) {
311 if(error) *error = "invalid WAVE file: unexpected EOF (010)";
312 return false;
314 if(!fm->format_block) {
315 if(error) *error = "invalid WAVE file: missing \"fmt \" chunk (011)";
316 return false;
318 if(!fm->audio_block) {
319 if(error) *error = "invalid WAVE file: missing \"data\" chunk (012)";
320 return false;
322 return true;
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)";
331 return false;
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)";
341 return false;
343 if(sizeof(FLAC__off_t) < 8) {
344 if(error) *error = "Wave64 is not supported on this compile (r00)";
345 return false;
347 if(!append_block_(fm, offset, 40, error))
348 return false;
349 eof_offset = (FLAC__off_t)unpack64le_(buffer+16); /*@@@ [2^63 limit] */
350 while(!feof(f)) {
351 FLAC__uint64 size;
352 if((offset = ftello(f)) < 0) {
353 if(error) *error = "ftello() error (003)";
354 return false;
356 if((size = fread(buffer, 1, 24, f)) < 24) {
357 if(size == 0 && feof(f))
358 break;
359 if(error) *error = "invalid Wave64 file (004)";
360 return false;
362 size = unpack64le_(buffer+16);
363 /* check if pad bytes needed */
364 if(size & 7)
365 size = (size+7) & (~((FLAC__uint64)7));
366 /* fmt GUID 20746D66-ACF3-11D3-8CD1-00C04F8EDB8A */
367 if(!memcmp(buffer, "\x66\x6D\x74\x20\xF3\xAC\xD3\x11\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)";
370 return false;
372 if(fm->audio_block) {
373 if(error) *error = "invalid Wave64 file: \"data\" chunk before \"fmt \" chunk (006)";
374 return false;
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)";
382 return false;
384 if(!fm->format_block) {
385 if(error) *error = "invalid Wave64 file: \"data\" chunk before \"fmt \" chunk (008)";
386 return false;
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))
391 return false;
392 /* skip to next chunk */
393 if(fseeko(f, size-24, SEEK_CUR) < 0) {
394 if(error) *error = "invalid Wave64 file: seek error (009)";
395 return false;
398 if(eof_offset != ftello(f)) {
399 if(error) *error = "invalid Wave64 file: unexpected EOF (010)";
400 return false;
402 if(!fm->format_block) {
403 if(error) *error = "invalid Wave64 file: missing \"fmt \" chunk (011)";
404 return false;
406 if(!fm->audio_block) {
407 if(error) *error = "invalid Wave64 file: missing \"data\" chunk (012)";
408 return false;
410 return true;
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 */
421 do {
422 /* even on the first chunk's loop there will be a skippable STREAMINFO block, on subsequent loops we are first moving past the PADDING we just used */
423 if(!FLAC__metadata_simple_iterator_next(it)) {
424 if(error) *error = "no matching PADDING block found (004)";
425 return false;
427 } while(FLAC__metadata_simple_iterator_get_block_type(it) != FLAC__METADATA_TYPE_PADDING);
428 if(FLAC__metadata_simple_iterator_get_block_length(it) != ID_LEN+fm->blocks[block_num].size) {
429 if(error) *error = "PADDING block with wrong size found (005)";
430 return false;
432 /* transfer chunk into APPLICATION block */
433 /* first set up the file pointers */
434 if(fseeko(fin, fm->blocks[block_num].offset, SEEK_SET) < 0) {
435 if(error) *error = "seek failed in WAVE/AIFF file (006)";
436 return false;
438 if(fseeko(fout, FLAC__metadata_simple_iterator_get_block_offset(it), SEEK_SET) < 0) {
439 if(error) *error = "seek failed in FLAC file (007)";
440 return false;
442 /* update the type */
443 buffer[0] = FLAC__METADATA_TYPE_APPLICATION;
444 if(FLAC__metadata_simple_iterator_is_last(it))
445 buffer[0] |= 0x80; /*MAGIC number*/
446 if(fwrite(buffer, 1, 1, fout) < 1) {
447 if(error) *error = "write failed in FLAC file (008)";
448 return false;
450 /* length stays the same so skip over it */
451 if(fseeko(fout, FLAC__STREAM_METADATA_LENGTH_LEN/8, SEEK_CUR) < 0) {
452 if(error) *error = "seek failed in FLAC file (009)";
453 return false;
455 /* write the APPLICATION ID */
456 memcpy(buffer, FLAC__FOREIGN_METADATA_APPLICATION_ID[fm->type], ID_LEN);
457 if(fwrite(buffer, 1, ID_LEN, fout) < ID_LEN) {
458 if(error) *error = "write failed in FLAC file (010)";
459 return false;
461 /* transfer the foreign metadata */
462 if(!copy_data_(fin, fout, fm->blocks[block_num].size, error, "read failed in WAVE/AIFF file (011)", "write failed in FLAC file (012)"))
463 return false;
464 block_num++;
466 return true;
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];
472 FLAC__off_t offset;
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)
479 continue;
480 if(!FLAC__metadata_simple_iterator_get_application_id(it, id)) {
481 if(error) *error = "FLAC__metadata_simple_iterator_get_application_id() error (002)";
482 return false;
484 if(memcmp(id, FLAC__FOREIGN_METADATA_APPLICATION_ID[fm->type], sizeof(id)))
485 continue;
486 offset = FLAC__metadata_simple_iterator_get_block_offset(it);
487 /* skip over header and app ID */
488 offset += (FLAC__STREAM_METADATA_IS_LAST_LEN + FLAC__STREAM_METADATA_TYPE_LEN + FLAC__STREAM_METADATA_LENGTH_LEN) / 8;
489 offset += sizeof(id);
490 /* look for format or audio blocks */
491 if(fseeko(f, offset, SEEK_SET) < 0) {
492 if(error) *error = "seek error (003)";
493 return false;
495 if(fread(buffer, 1, 4, f) != 4) {
496 if(error) *error = "read error (004)";
497 return false;
499 if(fm->num_blocks == 0) { /* first block? */
500 fm->is_rf64 = 0 == memcmp(buffer, "RF64", 4);
501 if(fm->type == FOREIGN_BLOCK_TYPE__RIFF && (0 == memcmp(buffer, "RIFF", 4) || fm->is_rf64))
502 type_found = true;
503 else if(fm->type == FOREIGN_BLOCK_TYPE__WAVE64 && 0 == memcmp(buffer, "riff", 4)) /* use first 4 bytes instead of whole GUID */
504 type_found = true;
505 else if(fm->type == FOREIGN_BLOCK_TYPE__AIFF && 0 == memcmp(buffer, "FORM", 4))
506 type_found = true;
507 else {
508 if(error) *error = "unsupported foreign metadata found, may need newer FLAC decoder (005)";
509 return false;
512 else if(!type_found) {
513 FLAC__ASSERT(0);
514 /* double protection: */
515 if(error) *error = "unsupported foreign metadata found, may need newer FLAC decoder (006)";
516 return false;
518 else if(fm->type == FOREIGN_BLOCK_TYPE__RIFF) {
519 if(!memcmp(buffer, "fmt ", 4)) {
520 if(fm->format_block) {
521 if(error) *error = "invalid WAVE metadata: multiple \"fmt \" chunks (007)";
522 return false;
524 if(fm->audio_block) {
525 if(error) *error = "invalid WAVE metadata: \"data\" chunk before \"fmt \" chunk (008)";
526 return false;
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)";
533 return false;
535 if(!fm->format_block) {
536 if(error) *error = "invalid WAVE metadata: \"data\" chunk before \"fmt \" chunk (010)";
537 return false;
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)";
544 return false;
546 ds64_found = true;
549 else if(fm->type == FOREIGN_BLOCK_TYPE__WAVE64) {
550 if(!memcmp(buffer, "fmt ", 4)) { /* use first 4 bytes instead of whole GUID */
551 if(fm->format_block) {
552 if(error) *error = "invalid Wave64 metadata: multiple \"fmt \" chunks (012)";
553 return false;
555 if(fm->audio_block) {
556 if(error) *error = "invalid Wave64 metadata: \"data\" chunk before \"fmt \" chunk (013)";
557 return false;
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)";
564 return false;
566 if(!fm->format_block) {
567 if(error) *error = "invalid Wave64 metadata: \"data\" chunk before \"fmt \" chunk (015)";
568 return false;
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)";
577 return false;
579 if(fm->audio_block) {
580 if(error) *error = "invalid AIFF metadata: \"SSND\" chunk before \"COMM\" chunk (017)";
581 return false;
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)";
588 return false;
590 if(!fm->format_block) {
591 if(error) *error = "invalid AIFF metadata: \"SSND\" chunk before \"COMM\" chunk (019)";
592 return false;
594 fm->audio_block = fm->num_blocks;
595 /* read SSND offset size */
596 if(fread(buffer+4, 1, 8, f) != 8) {
597 if(error) *error = "read error (020)";
598 return false;
600 fm->ssnd_offset_size = unpack32be_(buffer+8);
603 else {
604 FLAC__ASSERT(0);
605 /* double protection: */
606 if(error) *error = "unsupported foreign metadata found, may need newer FLAC decoder (021)";
607 return false;
609 if(!append_block_(fm, offset, FLAC__metadata_simple_iterator_get_block_length(it)-sizeof(id), error))
610 return false;
612 if(!type_found) {
613 if(error) *error = "no foreign metadata found (022)";
614 return false;
616 if(fm->is_rf64 && !ds64_found) {
617 if(error) *error = "invalid RF64 file: second chunk is not \"ds64\" (023)";
618 return false;
620 if(!fm->format_block) {
621 if(error)
622 *error =
623 fm->type==FOREIGN_BLOCK_TYPE__RIFF? "invalid WAVE file: missing \"fmt \" chunk (024)" :
624 fm->type==FOREIGN_BLOCK_TYPE__WAVE64? "invalid Wave64 file: missing \"fmt \" chunk (025)" :
625 "invalid AIFF file: missing \"COMM\" chunk (026)";
626 return false;
628 if(!fm->audio_block) {
629 if(error)
630 *error =
631 fm->type==FOREIGN_BLOCK_TYPE__RIFF? "invalid WAVE file: missing \"data\" chunk (027)" :
632 fm->type==FOREIGN_BLOCK_TYPE__WAVE64? "invalid Wave64 file: missing \"data\" chunk (028)" :
633 "invalid AIFF file: missing \"SSND\" chunk (029)";
634 return false;
636 return true;
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)
641 size_t i;
642 if(fseeko(fout, offset1, SEEK_SET) < 0) {
643 if(error) *error = "seek failed in WAVE/AIFF file (002)";
644 return false;
646 /* don't write first (RIFF/RF64/FORM) chunk, or ds64 chunk in the case of RF64 */
647 for(i = fm->is_rf64?2:1; i < fm->format_block; i++) {
648 if(fseeko(fin, fm->blocks[i].offset, SEEK_SET) < 0) {
649 if(error) *error = "seek failed in FLAC file (003)";
650 return false;
652 if(!copy_data_(fin, fout, fm->blocks[i].size, error, "read failed in WAVE/AIFF file (004)", "write failed in FLAC file (005)"))
653 return false;
655 if(fseeko(fout, offset2, SEEK_SET) < 0) {
656 if(error) *error = "seek failed in WAVE/AIFF file (006)";
657 return false;
659 for(i = fm->format_block+1; i < fm->audio_block; i++) {
660 if(fseeko(fin, fm->blocks[i].offset, SEEK_SET) < 0) {
661 if(error) *error = "seek failed in FLAC file (007)";
662 return false;
664 if(!copy_data_(fin, fout, fm->blocks[i].size, error, "read failed in WAVE/AIFF file (008)", "write failed in FLAC file (009)"))
665 return false;
667 if(fseeko(fout, offset3, SEEK_SET) < 0) {
668 if(error) *error = "seek failed in WAVE/AIFF file (010)";
669 return false;
671 for(i = fm->audio_block+1; i < fm->num_blocks; i++) {
672 if(fseeko(fin, fm->blocks[i].offset, SEEK_SET) < 0) {
673 if(error) *error = "seek failed in FLAC file (011)";
674 return false;
676 if(!copy_data_(fin, fout, fm->blocks[i].size, error, "read failed in WAVE/AIFF file (012)", "write failed in FLAC file (013)"))
677 return false;
679 return true;
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);
686 if(x) {
687 x->type = type;
688 x->is_rf64 = false;
690 return x;
693 void flac__foreign_metadata_delete(foreign_metadata_t *fm)
695 if(fm) {
696 if(fm->blocks)
697 free(fm->blocks);
698 free(fm);
702 FLAC__bool flac__foreign_metadata_read_from_aiff(foreign_metadata_t *fm, const char *filename, const char **error)
704 FLAC__bool ok;
705 FILE *f = fopen(filename, "rb");
706 if(!f) {
707 if(error) *error = "can't open AIFF file for reading (000)";
708 return false;
710 ok = read_from_aiff_(fm, f, error);
711 fclose(f);
712 return ok;
715 FLAC__bool flac__foreign_metadata_read_from_wave(foreign_metadata_t *fm, const char *filename, const char **error)
717 FLAC__bool ok;
718 FILE *f = fopen(filename, "rb");
719 if(!f) {
720 if(error) *error = "can't open WAVE file for reading (000)";
721 return false;
723 ok = read_from_wave_(fm, f, error);
724 fclose(f);
725 return ok;
728 FLAC__bool flac__foreign_metadata_read_from_wave64(foreign_metadata_t *fm, const char *filename, const char **error)
730 FLAC__bool ok;
731 FILE *f = fopen(filename, "rb");
732 if(!f) {
733 if(error) *error = "can't open Wave64 file for reading (000)";
734 return false;
736 ok = read_from_wave64_(fm, f, error);
737 fclose(f);
738 return ok;
741 FLAC__bool flac__foreign_metadata_write_to_flac(foreign_metadata_t *fm, const char *infilename, const char *outfilename, const char **error)
743 FLAC__bool ok;
744 FILE *fin, *fout;
745 FLAC__Metadata_SimpleIterator *it = FLAC__metadata_simple_iterator_new();
746 if(!it) {
747 if(error) *error = "out of memory (000)";
748 return false;
750 if(!FLAC__metadata_simple_iterator_init(it, outfilename, /*read_only=*/true, /*preserve_file_stats=*/false)) {
751 if(error) *error = "can't initialize iterator (001)";
752 FLAC__metadata_simple_iterator_delete(it);
753 return false;
755 if(0 == (fin = fopen(infilename, "rb"))) {
756 if(error) *error = "can't open WAVE/AIFF file for reading (002)";
757 FLAC__metadata_simple_iterator_delete(it);
758 return false;
760 if(0 == (fout = fopen(outfilename, "r+b"))) {
761 if(error) *error = "can't open FLAC file for updating (003)";
762 FLAC__metadata_simple_iterator_delete(it);
763 fclose(fin);
764 return false;
766 ok = write_to_flac_(fm, fin, fout, it, error);
767 FLAC__metadata_simple_iterator_delete(it);
768 fclose(fin);
769 fclose(fout);
770 return ok;
773 FLAC__bool flac__foreign_metadata_read_from_flac(foreign_metadata_t *fm, const char *filename, const char **error)
775 FLAC__bool ok;
776 FILE *f;
777 FLAC__Metadata_SimpleIterator *it = FLAC__metadata_simple_iterator_new();
778 if(!it) {
779 if(error) *error = "out of memory (000)";
780 return false;
782 if(!FLAC__metadata_simple_iterator_init(it, filename, /*read_only=*/true, /*preserve_file_stats=*/false)) {
783 if(error) *error = "can't initialize iterator (001)";
784 FLAC__metadata_simple_iterator_delete(it);
785 return false;
787 if(0 == (f = fopen(filename, "rb"))) {
788 if(error) *error = "can't open FLAC file for reading (002)";
789 FLAC__metadata_simple_iterator_delete(it);
790 return false;
792 ok = read_from_flac_(fm, f, it, error);
793 FLAC__metadata_simple_iterator_delete(it);
794 fclose(f);
795 return ok;
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)
800 FLAC__bool ok;
801 FILE *fin, *fout;
802 if(0 == (fin = fopen(infilename, "rb"))) {
803 if(error) *error = "can't open FLAC file for reading (000)";
804 return false;
806 if(0 == (fout = fopen(outfilename, "r+b"))) {
807 if(error) *error = "can't open WAVE/AIFF file for updating (001)";
808 fclose(fin);
809 return false;
811 ok = write_to_iff_(fm, fin, fout, offset1, offset2, offset3, error);
812 fclose(fin);
813 fclose(fout);
814 return ok;