Simplified logic of parsing sizes of rice-partitions
[flac.git] / src / flac / foreign_metadata.c
blob9ad9c1852d507c622e7fb77b251003571e0b23ef
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.
20 #ifdef HAVE_CONFIG_H
21 # include <config.h>
22 #endif
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"
33 #ifdef min
34 #undef min
35 #endif
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];
60 size_t left;
61 for(left = size; left > 0; ) {
62 size_t need = min(sizeof(buffer), left);
63 if(fread(buffer, 1, need, fin) < need) {
64 if(error) *error = read_error;
65 return false;
67 if(fwrite(buffer, 1, need, fout) < need) {
68 if(error) *error = write_error;
69 return false;
71 left -= need;
73 return true;
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/*)*/);
79 if(fb) {
80 fb[fm->num_blocks].offset = offset;
81 fb[fm->num_blocks].size = size;
82 fm->num_blocks++;
83 fm->blocks = fb;
84 return true;
86 if(error) *error = "out of memory";
87 return false;
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)";
96 return false;
98 if(fread(buffer, 1, 12, f) < 12 || memcmp(buffer, "FORM", 4) || (memcmp(buffer+8, "AIFF", 4) && memcmp(buffer+8, "AIFC", 4))) {
99 if(error) *error = "unsupported FORM layout (002)";
100 return false;
102 if(!append_block_(fm, offset, 12, error))
103 return false;
104 eof_offset = (FLAC__off_t)8 + (FLAC__off_t)unpack32be_(buffer+4);
105 while(!feof(f)) {
106 FLAC__uint32 size;
107 if((offset = ftello(f)) < 0) {
108 if(error) *error = "ftello() error (003)";
109 return false;
111 if((size = fread(buffer, 1, 8, f)) < 8) {
112 if(size == 0 && feof(f))
113 break;
114 if(error) *error = "invalid AIFF file (004)";
115 return false;
117 size = unpack32be_(buffer+4);
118 /* check if pad byte needed */
119 if(size & 1)
120 size++;
121 if(!memcmp(buffer, "COMM", 4)) {
122 if(fm->format_block) {
123 if(error) *error = "invalid AIFF file: multiple \"COMM\" chunks (005)";
124 return false;
126 if(fm->audio_block) {
127 if(error) *error = "invalid AIFF file: \"SSND\" chunk before \"COMM\" chunk (006)";
128 return false;
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)";
135 return false;
137 if(!fm->format_block) {
138 if(error) *error = "invalid AIFF file: \"SSND\" chunk before \"COMM\" chunk (008)";
139 return false;
141 fm->audio_block = fm->num_blocks;
142 /* read #offset bytes */
143 if(fread(buffer+8, 1, 4, f) < 4) {
144 if(error) *error = "invalid AIFF file (009)";
145 return false;
147 fm->ssnd_offset_size = unpack32be_(buffer+8);
148 if(fseeko(f, -4, SEEK_CUR) < 0) {
149 if(error) *error = "invalid AIFF file: seek error (010)";
150 return false;
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))
159 return false;
160 /* skip to next chunk */
161 if(fseeko(f, size, SEEK_CUR) < 0) {
162 if(error) *error = "invalid AIFF file: seek error (011)";
163 return false;
166 if(eof_offset != ftello(f)) {
167 if(error) *error = "invalid AIFF file: unexpected EOF (012)";
168 return false;
170 if(!fm->format_block) {
171 if(error) *error = "invalid AIFF file: missing \"COMM\" chunk (013)";
172 return false;
174 if(!fm->audio_block) {
175 if(error) *error = "invalid AIFF file: missing \"SSND\" chunk (014)";
176 return false;
178 return true;
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)";
187 return false;
189 if(fread(buffer, 1, 12, f) < 12 || (memcmp(buffer, "RIFF", 4) && memcmp(buffer, "RF64", 4)) || memcmp(buffer+8, "WAVE", 4)) {
190 if(error) *error = "unsupported RIFF layout (002)";
191 return false;
193 if(!memcmp(buffer, "RF64", 4))
194 fm->is_rf64 = true;
195 if(fm->is_rf64 && sizeof(FLAC__off_t) < 8) {
196 if(error) *error = "RF64 is not supported on this compile (r00)";
197 return false;
199 if(!append_block_(fm, offset, 12, error))
200 return false;
201 if(!fm->is_rf64 || unpack32le_(buffer+4) != 0xffffffff) {
202 eof_offset = (FLAC__off_t)8 + (FLAC__off_t)unpack32le_(buffer+4);
203 if(eof_offset & 1) /* fix odd RIFF size */
204 eof_offset++;
206 while(!feof(f)) {
207 FLAC__uint32 size;
208 if((offset = ftello(f)) < 0) {
209 if(error) *error = "ftello() error (003)";
210 return false;
212 if((size = fread(buffer, 1, 8, f)) < 8) {
213 if(size == 0 && feof(f))
214 break;
215 if(error) *error = "invalid WAVE file (004)";
216 return false;
218 size = unpack32le_(buffer+4);
219 /* check if pad byte needed */
220 if(size & 1)
221 size++;
222 if(!memcmp(buffer, "fmt ", 4)) {
223 if(fm->format_block) {
224 if(error) *error = "invalid WAVE file: multiple \"fmt \" chunks (005)";
225 return false;
227 if(fm->audio_block) {
228 if(error) *error = "invalid WAVE file: \"data\" chunk before \"fmt \" chunk (006)";
229 return false;
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)";
236 return false;
238 if(!fm->format_block) {
239 if(error) *error = "invalid WAVE file: \"data\" chunk before \"fmt \" chunk (008)";
240 return false;
242 fm->audio_block = fm->num_blocks;
243 if(fm->is_rf64 && fm->num_blocks < 2) {
244 if(error) *error = "invalid RF64 file: \"data\" chunk before \"ds64\" chunk (r01)";
245 return false;
248 if(!append_block_(fm, offset, 8 + (memcmp(buffer, "data", 4)? size : 0), error))
249 return false;
250 /* parse ds64 chunk if necessary */
251 if(fm->is_rf64 && fm->num_blocks == 2) {
252 FLAC__byte buffer2[7*4];
253 if(memcmp(buffer, "ds64", 4)) {
254 if(error) *error = "invalid RF64 file: \"ds64\" chunk does not immediately follow \"WAVE\" marker (r02)";
255 return false;
257 /* unpack the size again since we don't want the padding byte effect */
258 size = unpack32le_(buffer+4);
259 if(size < sizeof(buffer2)) {
260 if(error) *error = "invalid RF64 file: \"ds64\" chunk size is < 28 (r03)";
261 return false;
263 if(size > sizeof(buffer2)) {
264 if(error) *error = "RF64 file has \"ds64\" chunk with extra size table, which is not currently supported (r04)";
265 return false;
267 if(fread(buffer2, 1, sizeof(buffer2), f) < sizeof(buffer2)) {
268 if(error) *error = "unexpected EOF reading \"ds64\" chunk data in RF64 file (r05)";
269 return false;
271 ds64_data_size = (FLAC__off_t)unpack64le_(buffer2+8);
272 if(ds64_data_size == (FLAC__off_t)(-1)) {
273 if(error) *error = "RF64 file has \"ds64\" chunk with data size == -1 (r08)";
274 return false;
276 /* check if pad byte needed */
277 if(ds64_data_size & 1)
278 ds64_data_size++;
279 /* @@@ [2^63 limit] */
280 if(ds64_data_size < 0) {
281 if(error) *error = "RF64 file too large (r09)";
282 return false;
284 if(unpack32le_(buffer2+24)) {
285 if(error) *error = "RF64 file has \"ds64\" chunk with extra size table, which is not currently supported (r06)";
286 return false;
288 eof_offset = (FLAC__off_t)8 + (FLAC__off_t)unpack64le_(buffer2);
289 /* @@@ [2^63 limit] */
290 if((FLAC__off_t)unpack64le_(buffer2) < 0 || eof_offset < 0) {
291 if(error) *error = "RF64 file too large (r07)";
292 return false;
295 else { /* skip to next chunk */
296 if(fm->is_rf64 && !memcmp(buffer, "data", 4) && unpack32le_(buffer+4) == 0xffffffff) {
297 if(fseeko(f, ds64_data_size, SEEK_CUR) < 0) {
298 if(error) *error = "invalid RF64 file: seek error (r10)";
299 return false;
302 else {
303 if(fseeko(f, size, SEEK_CUR) < 0) {
304 if(error) *error = "invalid WAVE file: seek error (009)";
305 return false;
310 if(fm->is_rf64 && eof_offset == (FLAC__off_t)(-1)) {
311 if(error) *error = "invalid RF64 file: all RIFF sizes are -1 (r11)";
312 return false;
314 if(eof_offset != ftello(f)) {
315 if(error) *error = "invalid WAVE file: unexpected EOF (010)";
316 return false;
318 if(!fm->format_block) {
319 if(error) *error = "invalid WAVE file: missing \"fmt \" chunk (011)";
320 return false;
322 if(!fm->audio_block) {
323 if(error) *error = "invalid WAVE file: missing \"data\" chunk (012)";
324 return false;
326 return true;
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)";
335 return false;
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)";
345 return false;
347 if(sizeof(FLAC__off_t) < 8) {
348 if(error) *error = "Wave64 is not supported on this compile (r00)";
349 return false;
351 if(!append_block_(fm, offset, 40, error))
352 return false;
353 eof_offset = (FLAC__off_t)unpack64le_(buffer+16); /*@@@ [2^63 limit] */
354 while(!feof(f)) {
355 FLAC__uint64 size;
356 if((offset = ftello(f)) < 0) {
357 if(error) *error = "ftello() error (003)";
358 return false;
360 if((size = fread(buffer, 1, 24, f)) < 24) {
361 if(size == 0 && feof(f))
362 break;
363 if(error) *error = "invalid Wave64 file (004)";
364 return false;
366 size = unpack64le_(buffer+16);
367 /* check if pad bytes needed */
368 if(size & 7)
369 size = (size+7) & (~((FLAC__uint64)7));
370 /* fmt GUID 20746D66-ACF3-11D3-8CD1-00C04F8EDB8A */
371 if(!memcmp(buffer, "\x66\x6D\x74\x20\xF3\xAC\xD3\x11\x8C\xD1\x00\xC0\x4F\x8E\xDB\x8A", 16)) {
372 if(fm->format_block) {
373 if(error) *error = "invalid Wave64 file: multiple \"fmt \" chunks (005)";
374 return false;
376 if(fm->audio_block) {
377 if(error) *error = "invalid Wave64 file: \"data\" chunk before \"fmt \" chunk (006)";
378 return false;
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)";
386 return false;
388 if(!fm->format_block) {
389 if(error) *error = "invalid Wave64 file: \"data\" chunk before \"fmt \" chunk (008)";
390 return false;
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))
395 return false;
396 /* skip to next chunk */
397 if(fseeko(f, size-24, SEEK_CUR) < 0) {
398 if(error) *error = "invalid Wave64 file: seek error (009)";
399 return false;
402 if(eof_offset != ftello(f)) {
403 if(error) *error = "invalid Wave64 file: unexpected EOF (010)";
404 return false;
406 if(!fm->format_block) {
407 if(error) *error = "invalid Wave64 file: missing \"fmt \" chunk (011)";
408 return false;
410 if(!fm->audio_block) {
411 if(error) *error = "invalid Wave64 file: missing \"data\" chunk (012)";
412 return false;
414 return true;
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 */
425 do {
426 /* even on the first chunk's loop there will be a skippable STREAMINFO block, on subsequent loops we are first moving past the PADDING we just used */
427 if(!FLAC__metadata_simple_iterator_next(it)) {
428 if(error) *error = "no matching PADDING block found (004)";
429 return false;
431 } while(FLAC__metadata_simple_iterator_get_block_type(it) != FLAC__METADATA_TYPE_PADDING);
432 if(FLAC__metadata_simple_iterator_get_block_length(it) != ID_LEN+fm->blocks[block_num].size) {
433 if(error) *error = "PADDING block with wrong size found (005)";
434 return false;
436 /* transfer chunk into APPLICATION block */
437 /* first set up the file pointers */
438 if(fseeko(fin, fm->blocks[block_num].offset, SEEK_SET) < 0) {
439 if(error) *error = "seek failed in WAVE/AIFF file (006)";
440 return false;
442 if(fseeko(fout, FLAC__metadata_simple_iterator_get_block_offset(it), SEEK_SET) < 0) {
443 if(error) *error = "seek failed in FLAC file (007)";
444 return false;
446 /* update the type */
447 buffer[0] = FLAC__METADATA_TYPE_APPLICATION;
448 if(FLAC__metadata_simple_iterator_is_last(it))
449 buffer[0] |= 0x80; /*MAGIC number*/
450 if(fwrite(buffer, 1, 1, fout) < 1) {
451 if(error) *error = "write failed in FLAC file (008)";
452 return false;
454 /* length stays the same so skip over it */
455 if(fseeko(fout, FLAC__STREAM_METADATA_LENGTH_LEN/8, SEEK_CUR) < 0) {
456 if(error) *error = "seek failed in FLAC file (009)";
457 return false;
459 /* write the APPLICATION ID */
460 memcpy(buffer, FLAC__FOREIGN_METADATA_APPLICATION_ID[fm->type], ID_LEN);
461 if(fwrite(buffer, 1, ID_LEN, fout) < ID_LEN) {
462 if(error) *error = "write failed in FLAC file (010)";
463 return false;
465 /* transfer the foreign metadata */
466 if(!copy_data_(fin, fout, fm->blocks[block_num].size, error, "read failed in WAVE/AIFF file (011)", "write failed in FLAC file (012)"))
467 return false;
468 block_num++;
470 return true;
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];
476 FLAC__off_t offset;
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)
483 continue;
484 if(!FLAC__metadata_simple_iterator_get_application_id(it, id)) {
485 if(error) *error = "FLAC__metadata_simple_iterator_get_application_id() error (002)";
486 return false;
488 if(memcmp(id, FLAC__FOREIGN_METADATA_APPLICATION_ID[fm->type], sizeof(id)))
489 continue;
490 offset = FLAC__metadata_simple_iterator_get_block_offset(it);
491 /* skip over header and app ID */
492 offset += (FLAC__STREAM_METADATA_IS_LAST_LEN + FLAC__STREAM_METADATA_TYPE_LEN + FLAC__STREAM_METADATA_LENGTH_LEN) / 8;
493 offset += sizeof(id);
494 /* look for format or audio blocks */
495 if(fseeko(f, offset, SEEK_SET) < 0) {
496 if(error) *error = "seek error (003)";
497 return false;
499 if(fread(buffer, 1, 4, f) != 4) {
500 if(error) *error = "read error (004)";
501 return false;
503 if(fm->num_blocks == 0) { /* first block? */
504 fm->is_rf64 = 0 == memcmp(buffer, "RF64", 4);
505 if(fm->type == FOREIGN_BLOCK_TYPE__RIFF && (0 == memcmp(buffer, "RIFF", 4) || fm->is_rf64))
506 type_found = true;
507 else if(fm->type == FOREIGN_BLOCK_TYPE__WAVE64 && 0 == memcmp(buffer, "riff", 4)) /* use first 4 bytes instead of whole GUID */
508 type_found = true;
509 else if(fm->type == FOREIGN_BLOCK_TYPE__AIFF && 0 == memcmp(buffer, "FORM", 4))
510 type_found = true;
511 else {
512 if(error) *error = "unsupported foreign metadata found, may need newer FLAC decoder (005)";
513 return false;
516 else if(!type_found) {
517 FLAC__ASSERT(0);
518 /* double protection: */
519 if(error) *error = "unsupported foreign metadata found, may need newer FLAC decoder (006)";
520 return false;
522 else if(fm->type == FOREIGN_BLOCK_TYPE__RIFF) {
523 if(!memcmp(buffer, "fmt ", 4)) {
524 if(fm->format_block) {
525 if(error) *error = "invalid WAVE metadata: multiple \"fmt \" chunks (007)";
526 return false;
528 if(fm->audio_block) {
529 if(error) *error = "invalid WAVE metadata: \"data\" chunk before \"fmt \" chunk (008)";
530 return false;
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)";
537 return false;
539 if(!fm->format_block) {
540 if(error) *error = "invalid WAVE metadata: \"data\" chunk before \"fmt \" chunk (010)";
541 return false;
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)";
548 return false;
550 ds64_found = true;
553 else if(fm->type == FOREIGN_BLOCK_TYPE__WAVE64) {
554 if(!memcmp(buffer, "fmt ", 4)) { /* use first 4 bytes instead of whole GUID */
555 if(fm->format_block) {
556 if(error) *error = "invalid Wave64 metadata: multiple \"fmt \" chunks (012)";
557 return false;
559 if(fm->audio_block) {
560 if(error) *error = "invalid Wave64 metadata: \"data\" chunk before \"fmt \" chunk (013)";
561 return false;
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)";
568 return false;
570 if(!fm->format_block) {
571 if(error) *error = "invalid Wave64 metadata: \"data\" chunk before \"fmt \" chunk (015)";
572 return false;
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)";
581 return false;
583 if(fm->audio_block) {
584 if(error) *error = "invalid AIFF metadata: \"SSND\" chunk before \"COMM\" chunk (017)";
585 return false;
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)";
592 return false;
594 if(!fm->format_block) {
595 if(error) *error = "invalid AIFF metadata: \"SSND\" chunk before \"COMM\" chunk (019)";
596 return false;
598 fm->audio_block = fm->num_blocks;
599 /* read SSND offset size */
600 if(fread(buffer+4, 1, 8, f) != 8) {
601 if(error) *error = "read error (020)";
602 return false;
604 fm->ssnd_offset_size = unpack32be_(buffer+8);
607 else {
608 FLAC__ASSERT(0);
609 /* double protection: */
610 if(error) *error = "unsupported foreign metadata found, may need newer FLAC decoder (021)";
611 return false;
613 if(!append_block_(fm, offset, FLAC__metadata_simple_iterator_get_block_length(it)-sizeof(id), error))
614 return false;
616 if(!type_found) {
617 if(error) *error = "no foreign metadata found (022)";
618 return false;
620 if(fm->is_rf64 && !ds64_found) {
621 if(error) *error = "invalid RF64 file: second chunk is not \"ds64\" (023)";
622 return false;
624 if(!fm->format_block) {
625 if(error)
626 *error =
627 fm->type==FOREIGN_BLOCK_TYPE__RIFF? "invalid WAVE file: missing \"fmt \" chunk (024)" :
628 fm->type==FOREIGN_BLOCK_TYPE__WAVE64? "invalid Wave64 file: missing \"fmt \" chunk (025)" :
629 "invalid AIFF file: missing \"COMM\" chunk (026)";
630 return false;
632 if(!fm->audio_block) {
633 if(error)
634 *error =
635 fm->type==FOREIGN_BLOCK_TYPE__RIFF? "invalid WAVE file: missing \"data\" chunk (027)" :
636 fm->type==FOREIGN_BLOCK_TYPE__WAVE64? "invalid Wave64 file: missing \"data\" chunk (028)" :
637 "invalid AIFF file: missing \"SSND\" chunk (029)";
638 return false;
640 return true;
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)
645 size_t i;
646 if(fseeko(fout, offset1, SEEK_SET) < 0) {
647 if(error) *error = "seek failed in WAVE/AIFF file (002)";
648 return false;
650 /* don't write first (RIFF/RF64/FORM) chunk, or ds64 chunk in the case of RF64 */
651 for(i = fm->is_rf64?2:1; i < fm->format_block; i++) {
652 if(fseeko(fin, fm->blocks[i].offset, SEEK_SET) < 0) {
653 if(error) *error = "seek failed in FLAC file (003)";
654 return false;
656 if(!copy_data_(fin, fout, fm->blocks[i].size, error, "read failed in WAVE/AIFF file (004)", "write failed in FLAC file (005)"))
657 return false;
659 if(fseeko(fout, offset2, SEEK_SET) < 0) {
660 if(error) *error = "seek failed in WAVE/AIFF file (006)";
661 return false;
663 for(i = fm->format_block+1; i < fm->audio_block; i++) {
664 if(fseeko(fin, fm->blocks[i].offset, SEEK_SET) < 0) {
665 if(error) *error = "seek failed in FLAC file (007)";
666 return false;
668 if(!copy_data_(fin, fout, fm->blocks[i].size, error, "read failed in WAVE/AIFF file (008)", "write failed in FLAC file (009)"))
669 return false;
671 if(fseeko(fout, offset3, SEEK_SET) < 0) {
672 if(error) *error = "seek failed in WAVE/AIFF file (010)";
673 return false;
675 for(i = fm->audio_block+1; i < fm->num_blocks; i++) {
676 if(fseeko(fin, fm->blocks[i].offset, SEEK_SET) < 0) {
677 if(error) *error = "seek failed in FLAC file (011)";
678 return false;
680 if(!copy_data_(fin, fout, fm->blocks[i].size, error, "read failed in WAVE/AIFF file (012)", "write failed in FLAC file (013)"))
681 return false;
683 return true;
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);
690 if(x) {
691 x->type = type;
692 x->is_rf64 = false;
694 return x;
697 void flac__foreign_metadata_delete(foreign_metadata_t *fm)
699 if(fm) {
700 if(fm->blocks)
701 free(fm->blocks);
702 free(fm);
706 FLAC__bool flac__foreign_metadata_read_from_aiff(foreign_metadata_t *fm, const char *filename, const char **error)
708 FLAC__bool ok;
709 FILE *f = flac_fopen(filename, "rb");
710 if(!f) {
711 if(error) *error = "can't open AIFF file for reading (000)";
712 return false;
714 ok = read_from_aiff_(fm, f, error);
715 fclose(f);
716 return ok;
719 FLAC__bool flac__foreign_metadata_read_from_wave(foreign_metadata_t *fm, const char *filename, const char **error)
721 FLAC__bool ok;
722 FILE *f = flac_fopen(filename, "rb");
723 if(!f) {
724 if(error) *error = "can't open WAVE file for reading (000)";
725 return false;
727 ok = read_from_wave_(fm, f, error);
728 fclose(f);
729 return ok;
732 FLAC__bool flac__foreign_metadata_read_from_wave64(foreign_metadata_t *fm, const char *filename, const char **error)
734 FLAC__bool ok;
735 FILE *f = flac_fopen(filename, "rb");
736 if(!f) {
737 if(error) *error = "can't open Wave64 file for reading (000)";
738 return false;
740 ok = read_from_wave64_(fm, f, error);
741 fclose(f);
742 return ok;
745 FLAC__bool flac__foreign_metadata_write_to_flac(foreign_metadata_t *fm, const char *infilename, const char *outfilename, const char **error)
747 FLAC__bool ok;
748 FILE *fin, *fout;
749 FLAC__Metadata_SimpleIterator *it = FLAC__metadata_simple_iterator_new();
750 if(!it) {
751 if(error) *error = "out of memory (000)";
752 return false;
754 if(!FLAC__metadata_simple_iterator_init(it, outfilename, /*read_only=*/true, /*preserve_file_stats=*/false)) {
755 if(error) *error = "can't initialize iterator (001)";
756 FLAC__metadata_simple_iterator_delete(it);
757 return false;
759 if(0 == (fin = flac_fopen(infilename, "rb"))) {
760 if(error) *error = "can't open WAVE/AIFF file for reading (002)";
761 FLAC__metadata_simple_iterator_delete(it);
762 return false;
764 if(0 == (fout = flac_fopen(outfilename, "r+b"))) {
765 if(error) *error = "can't open FLAC file for updating (003)";
766 FLAC__metadata_simple_iterator_delete(it);
767 fclose(fin);
768 return false;
770 ok = write_to_flac_(fm, fin, fout, it, error);
771 FLAC__metadata_simple_iterator_delete(it);
772 fclose(fin);
773 fclose(fout);
774 return ok;
777 FLAC__bool flac__foreign_metadata_read_from_flac(foreign_metadata_t *fm, const char *filename, const char **error)
779 FLAC__bool ok;
780 FILE *f;
781 FLAC__Metadata_SimpleIterator *it = FLAC__metadata_simple_iterator_new();
782 if(!it) {
783 if(error) *error = "out of memory (000)";
784 return false;
786 if(!FLAC__metadata_simple_iterator_init(it, filename, /*read_only=*/true, /*preserve_file_stats=*/false)) {
787 if(error) *error = "can't initialize iterator (001)";
788 FLAC__metadata_simple_iterator_delete(it);
789 return false;
791 if(0 == (f = flac_fopen(filename, "rb"))) {
792 if(error) *error = "can't open FLAC file for reading (002)";
793 FLAC__metadata_simple_iterator_delete(it);
794 return false;
796 ok = read_from_flac_(fm, f, it, error);
797 FLAC__metadata_simple_iterator_delete(it);
798 fclose(f);
799 return ok;
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)
804 FLAC__bool ok;
805 FILE *fin, *fout;
806 if(0 == (fin = flac_fopen(infilename, "rb"))) {
807 if(error) *error = "can't open FLAC file for reading (000)";
808 return false;
810 if(0 == (fout = flac_fopen(outfilename, "r+b"))) {
811 if(error) *error = "can't open WAVE/AIFF file for updating (001)";
812 fclose(fin);
813 return false;
815 ok = write_to_iff_(fm, fin, fout, offset1, offset2, offset3, error);
816 fclose(fin);
817 fclose(fout);
818 return ok;