fd.c: Change return value of file_exists() to bool.
[paraslash.git] / flac_afh.c
1 /* Copyright (C) 2011 Andre Noll <maan@tuebingen.mpg.de>, see file COPYING. */
2
3 /** \file flac_afh.c Audio format handler for flac files. */
4
5 #include <regex.h>
6 #include <FLAC/stream_decoder.h>
7 #include <FLAC/metadata.h>
8
9 #include "para.h"
10 #include "error.h"
11 #include "afh.h"
12 #include "string.h"
13 #include "fd.h"
14
15 struct private_flac_afh_data {
16         const char *map;
17         size_t map_bytes;
18         size_t fpos;
19         struct afh_info *afhi;
20         unsigned blocksize;
21 };
22
23 static size_t copy_data(struct private_flac_afh_data *pfad, void *buf,
24                 size_t want)
25 {
26         size_t copy, have = pfad->map_bytes - pfad->fpos;
27
28         if (have == 0)
29                 return 0;
30         copy = have < want? have : want;
31         memcpy(buf, pfad->map + pfad->fpos, copy);
32         pfad->fpos += copy;
33         return copy;
34 }
35
36 static size_t meta_read_cb(void *ptr, size_t size, size_t nmemb,
37                 FLAC__IOHandle handle)
38 {
39         struct private_flac_afh_data *pfad = handle;
40         return copy_data(pfad, ptr, nmemb * size);
41 }
42
43 static int meta_seek_cb(FLAC__IOHandle handle, FLAC__int64 offset, int whence)
44 {
45         struct private_flac_afh_data *pfad = handle;
46
47         if (offset < 0)
48                 return -1;
49
50         switch (whence) {
51         case SEEK_SET:
52                 if (offset >= pfad->map_bytes)
53                         return -1;
54                 pfad->fpos = offset;
55                 return 0;
56         case SEEK_CUR:
57                 if (pfad->fpos + offset >= pfad->map_bytes)
58                         return -1;
59                 pfad->fpos += offset;
60                 return 0;
61         case SEEK_END:
62                 if (offset >= pfad->map_bytes)
63                         return -1;
64                 pfad->fpos = offset;
65                 return 0;
66         default:
67                 return -1;
68         }
69 }
70
71 static FLAC__int64 meta_tell_cb(FLAC__IOHandle handle)
72 {
73         struct private_flac_afh_data *pfad = handle;
74         return pfad->fpos;
75 }
76
77 static int meta_eof_cb(FLAC__IOHandle handle)
78 {
79         struct private_flac_afh_data *pfad = handle;
80         return pfad->fpos == pfad->map_bytes;
81 }
82
83 static int meta_close_cb(FLAC__IOHandle __a_unused handle)
84 {
85         return 0;
86 }
87
88 static const FLAC__IOCallbacks meta_callbacks = {
89         .read = meta_read_cb,
90         .write = NULL,
91         .seek = meta_seek_cb,
92         .tell = meta_tell_cb,
93         .eof = meta_eof_cb,
94         .close = meta_close_cb
95 };
96
97 static void free_tags(struct taginfo *tags)
98 {
99         freep(&tags->artist);
100         freep(&tags->title);
101         freep(&tags->album);
102         freep(&tags->year);
103         freep(&tags->comment);
104 }
105
106 static bool copy_if_tag_type(const char *tag, int taglen, const char *type,
107                 char **p)
108 {
109         char *q = key_value_copy(tag, taglen, type);
110         if (!q)
111                 return false;
112         free(*p);
113         *p = q;
114         return true;
115 }
116
117 static void flac_read_vorbis_comments(FLAC__StreamMetadata_VorbisComment *vc,
118                 struct taginfo *tags)
119 {
120         int i;
121         FLAC__StreamMetadata_VorbisComment_Entry *comment = vc->comments;
122
123         PARA_INFO_LOG("found %u vorbis comments\n", vc->num_comments);
124         for (i = 0; i < vc->num_comments; i++) {
125                 char *e = (char *)comment[i].entry;
126                 int len = comment[i].length;
127                 if (copy_if_tag_type(e, len, "artist", &tags->artist))
128                         continue;
129                 if (copy_if_tag_type(e, len, "title", &tags->title))
130                         continue;
131                 if (copy_if_tag_type(e, len, "album", &tags->album))
132                         continue;
133                 if (copy_if_tag_type(e, len, "year", &tags->year))
134                         continue;
135                 if (copy_if_tag_type(e, len, "comment", &tags->comment))
136                         continue;
137         }
138 }
139
140 /*
141  * FLAC__metadata_object_vorbiscomment_replace_comment() is buggy in some
142  * libFLAC versions (see commit e95399c1 in the flac git repository). Hence we
143  * use delete and add as a workaround.
144  */
145 static int flac_replace_vorbis_comment(FLAC__StreamMetadata *b,
146                 const char *tag, const char* val)
147 {
148         FLAC__bool ok;
149         FLAC__StreamMetadata_VorbisComment_Entry entry;
150         int ret;
151
152         PARA_INFO_LOG("replacing %s\n", tag);
153         ret = FLAC__metadata_object_vorbiscomment_remove_entries_matching(
154                 b, tag);
155         if (ret < 0)
156                 return -E_FLAC_REPLACE_COMMENT;
157         ok = FLAC__metadata_object_vorbiscomment_entry_from_name_value_pair(
158                 &entry, tag, val? val : "");
159         if (!ok)
160                 return -E_FLAC_REPLACE_COMMENT;
161         ok = FLAC__metadata_object_vorbiscomment_append_comment(b, entry,
162                 false /* no copy */);
163         if (!ok) {
164                 free(entry.entry);
165                 return -E_FLAC_REPLACE_COMMENT;
166         }
167         return 1;
168 }
169
170 static int flac_replace_vorbis_comments(FLAC__Metadata_Chain *chain,
171                 FLAC__StreamMetadata *b, struct taginfo *tags)
172 {
173         FLAC__bool ok;
174         int ret;
175
176         ret = flac_replace_vorbis_comment(b, "artist", tags->artist);
177         if (ret < 0)
178                 return ret;
179         ret = flac_replace_vorbis_comment(b, "title", tags->title);
180         if (ret < 0)
181                 return ret;
182         ret = flac_replace_vorbis_comment(b, "album", tags->album);
183         if (ret < 0)
184                 return ret;
185         ret = flac_replace_vorbis_comment(b, "year", tags->year);
186         if (ret < 0)
187                 return ret;
188         ret = flac_replace_vorbis_comment(b, "comment", tags->comment);
189         if (ret < 0)
190                 return ret;
191         /*
192          * Even if padding is disabled, libflac will try to modify the original
193          * file inplace if the metadata size has not changed. This won't work
194          * here though, because the original file is mapped read-only. Since
195          * there is no option to force the use of a temp file we work around
196          * this shortcoming by adding a dummy entry which increases the size of
197          * the meta data. If the entry already exists, we simply remove it.
198          */
199         ok = FLAC__metadata_chain_check_if_tempfile_needed(chain,
200                 false /* no padding */);
201         if (!ok) {
202                 PARA_INFO_LOG("adding/removing dummy comment\n");
203                 ret = FLAC__metadata_object_vorbiscomment_remove_entries_matching(
204                         b, "comment2");
205                 if (ret < 0)
206                         return -E_FLAC_REPLACE_COMMENT;
207                 if (ret == 0) { /* nothing was removed */
208                         ret = flac_replace_vorbis_comment(b, "comment2",
209                                 "avoid inplace write");
210                         if (ret < 0)
211                                 return ret;
212                 }
213                 assert(FLAC__metadata_chain_check_if_tempfile_needed(chain,
214                         false /* no padding */));
215         }
216         return 1;
217 }
218
219 static int flac_init_meta(struct private_flac_afh_data *pfad,
220                 FLAC__Metadata_Chain **chainp, FLAC__Metadata_Iterator **iterp)
221 {
222         int ret;
223         FLAC__bool ok;
224         FLAC__Metadata_Chain *chain;
225         FLAC__Metadata_Iterator *iter;
226
227         *chainp = NULL;
228         *iterp = NULL;
229         chain = FLAC__metadata_chain_new();
230         if (!chain)
231                 return -E_FLAC_CHAIN_ALLOC;
232         ret = -E_FLAC_CHAIN_READ;
233         ok = FLAC__metadata_chain_read_with_callbacks(chain, pfad,
234                 meta_callbacks);
235         if (!ok)
236                 goto free_chain;
237         ret = -E_FLAC_ITER_ALLOC;
238         iter = FLAC__metadata_iterator_new();
239         if (!iter)
240                 goto free_chain;
241         FLAC__metadata_iterator_init(iter, chain);
242         *iterp = iter;
243         *chainp = chain;
244         return 1;
245 free_chain:
246         FLAC__metadata_chain_delete(chain);
247         return ret;
248 }
249
250 static int flac_read_meta(struct private_flac_afh_data *pfad)
251 {
252         int ret;
253         FLAC__Metadata_Chain *chain;
254         FLAC__Metadata_Iterator *iter;
255         FLAC__StreamMetadata_StreamInfo *info = NULL;
256         FLAC__bool ok;
257
258         ret = flac_init_meta(pfad, &chain, &iter);
259         if (ret < 0)
260                 return ret;
261         for (;;) {
262                 FLAC__StreamMetadata *b;
263                 b = FLAC__metadata_iterator_get_block(iter);
264                 if (!b)
265                         break;
266                 if (b->type == FLAC__METADATA_TYPE_STREAMINFO) {
267                         info = &b->data.stream_info;
268                         ret = -E_FLAC_VARBLOCK;
269                         if (info->min_blocksize != info->max_blocksize)
270                                 goto free_iter;
271                         pfad->afhi->frequency = info->sample_rate;
272                         pfad->afhi->channels = info->channels;
273                         pfad->blocksize = info->min_blocksize;
274                 }
275                 if (b->type == FLAC__METADATA_TYPE_VORBIS_COMMENT)
276                         flac_read_vorbis_comments(&b->data.vorbis_comment,
277                                 &pfad->afhi->tags);
278                 ok = FLAC__metadata_iterator_next(iter);
279                 if (!ok)
280                         break;
281         }
282         ret = info? 0: -E_FLAC_STREAMINFO;
283 free_iter:
284         FLAC__metadata_iterator_delete(iter);
285         FLAC__metadata_chain_delete(chain);
286         if (ret < 0)
287                 free_tags(&pfad->afhi->tags);
288         return ret;
289 }
290
291 static FLAC__StreamDecoderReadStatus read_cb(
292                 __a_unused const FLAC__StreamDecoder *decoder,
293                 FLAC__byte buffer[], size_t *bytes, void *client_data)
294 {
295         struct private_flac_afh_data *pfad = client_data;
296
297         assert(*bytes > 0);
298         *bytes = copy_data(pfad, buffer, *bytes);
299         if (*bytes == 0)
300                 return FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM;
301         else
302                 return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE;
303 }
304
305 static FLAC__StreamDecoderTellStatus tell_cb(
306                 __a_unused const FLAC__StreamDecoder *decoder,
307                 FLAC__uint64 *absolute_byte_offset, void *client_data)
308 {
309         struct private_flac_afh_data *pfad = client_data;
310
311         *absolute_byte_offset = pfad->fpos;
312         return FLAC__STREAM_DECODER_TELL_STATUS_OK;
313 }
314
315 /* libflac insists on this callback being present. */
316 static FLAC__StreamDecoderWriteStatus write_cb(
317                 __a_unused const FLAC__StreamDecoder *decoder,
318                 __a_unused const FLAC__Frame *frame,
319                 __a_unused const FLAC__int32 *const buffer[],
320                 __a_unused void *client_data)
321 {
322         return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
323 }
324
325 static void error_cb(
326                 __a_unused const FLAC__StreamDecoder *decoder,
327                 FLAC__StreamDecoderErrorStatus status,
328                 __a_unused void *client_data)
329 {
330         PARA_ERROR_LOG("%s\n", FLAC__StreamDecoderErrorStatusString[status]);
331 }
332
333 static int flac_afh_read_chunks(struct private_flac_afh_data *pfad)
334 {
335         FLAC__StreamDecoder *decoder;
336         FLAC__StreamDecoderInitStatus init_status;
337         FLAC__bool ok;
338         FLAC__uint64 c;
339         unsigned chunk_table_size = 0;
340         int ret;
341         struct afh_info *afhi = pfad->afhi;
342
343         PARA_INFO_LOG("reading chunk table\n");
344         afhi->chunk_table = NULL;
345         decoder = FLAC__stream_decoder_new();
346         if (!decoder)
347                 return -E_FLAC_AFH_DECODER_ALLOC;
348         ret = -E_FLAC_AFH_DECODER_INIT;
349         init_status = FLAC__stream_decoder_init_stream(
350                 decoder,
351                 read_cb,
352                 NULL, /* seek */
353                 tell_cb,
354                 NULL, /* length */
355                 NULL, /* eof */
356                 write_cb,
357                 NULL,
358                 error_cb,
359                 pfad
360         );
361         if (init_status != FLAC__STREAM_DECODER_INIT_STATUS_OK)
362                 goto free_decoder;
363         ret = -E_FLAC_SKIP_META;
364         ok = FLAC__stream_decoder_process_until_end_of_metadata(decoder);
365         if (!ok)
366                 goto free_decoder;
367         for (c = 0;; c++) {
368                 FLAC__uint64 pos;
369                 FLAC__StreamDecoderState state;
370
371                 ret = -E_FLAC_DECODE_POS;
372                 ok = FLAC__stream_decoder_get_decode_position(decoder, &pos);
373                 if (!ok)
374                         goto free_decoder;
375                 if (c >= chunk_table_size) {
376                         chunk_table_size = 2 * chunk_table_size + 100;
377                         afhi->chunk_table = para_realloc(afhi->chunk_table,
378                                 chunk_table_size * sizeof(uint32_t));
379                 }
380                 afhi->chunk_table[c] = pos;
381
382                 ok = FLAC__stream_decoder_skip_single_frame(decoder);
383                 if (!ok)
384                         break;
385                 state = FLAC__stream_decoder_get_state(decoder);
386                 if (state == FLAC__STREAM_DECODER_END_OF_STREAM)
387                         break;
388         }
389         afhi->chunks_total = c;
390         set_max_chunk_size(afhi);
391         ret = 1;
392 free_decoder:
393         FLAC__stream_decoder_finish(decoder);
394         FLAC__stream_decoder_delete(decoder);
395         if (ret < 0)
396                 freep(&afhi->chunk_table);
397         return ret;
398 }
399
400 static int flac_get_file_info(char *map, size_t map_bytes, __a_unused int fd,
401                 struct afh_info *afhi)
402 {
403         struct private_flac_afh_data pfad_struct = {
404                 .map = map,
405                 .map_bytes = map_bytes,
406                 .afhi = afhi
407         }, *pfad = &pfad_struct;
408         int ret;
409         double chunk_time;
410
411         afhi->header_len = 0;
412         ret = flac_read_meta(pfad);
413         if (ret < 0)
414                 return ret;
415         pfad->fpos = 0;
416         ret = flac_afh_read_chunks(pfad);
417         if (ret < 0) {
418                 free_tags(&afhi->tags);
419                 return ret;
420         }
421         afhi->techinfo = make_message("blocksize: %u", pfad->blocksize);
422         afhi->seconds_total = DIV_ROUND_UP(afhi->chunks_total * pfad->blocksize,
423                 afhi->frequency);
424         afhi->bitrate = pfad->map_bytes * 8 / afhi->seconds_total / 1024;
425         chunk_time = (double)pfad->blocksize / afhi->frequency;
426         afhi->chunk_tv.tv_sec = chunk_time;
427         chunk_time *= 1000 * 1000;
428         chunk_time -= afhi->chunk_tv.tv_sec * 1000 * 1000;
429         afhi->chunk_tv.tv_usec = chunk_time;
430         return 1;
431 }
432
433 static size_t temp_write_cb(const void *ptr, size_t size, size_t nmemb,
434         FLAC__IOHandle handle)
435 {
436         int ret, fd = *(int *)handle;
437         size_t n = size * nmemb; /* FIXME: possible overflow */
438
439         ret = write_all(fd, ptr, n);
440
441         /*
442          * libflac expects POSIX semantics: If an error occurs, or the end of
443          * the file is reached, the return value is a short item count or zero.
444          */
445         if (ret < 0) {
446                 PARA_ERROR_LOG("%s\n", para_strerror(-ret));
447                 return 0;
448         }
449         return nmemb;
450 }
451
452 /* only the write callback needs to be supplied for writing the temp file. */
453 static const FLAC__IOCallbacks temp_callbacks = {
454         .write = temp_write_cb,
455 };
456
457 static int flac_write_chain(FLAC__Metadata_Chain *chain,
458                 struct private_flac_afh_data *pfad, int fd)
459 {
460         FLAC__bool ok;
461
462         ok = FLAC__metadata_chain_write_with_callbacks_and_tempfile(chain,
463                 false /* no padding*/, pfad,
464                 meta_callbacks, &fd, temp_callbacks);
465         if (!ok) {
466                 FLAC__Metadata_ChainStatus st;
467                 st = FLAC__metadata_chain_status(chain);
468                 PARA_ERROR_LOG("chain status: %u\n", st);
469                 if (st == FLAC__METADATA_CHAIN_STATUS_READ_ERROR)
470                         PARA_ERROR_LOG("read error\n");
471                 return -E_FLAC_WRITE_CHAIN;
472         }
473         return 1;
474 }
475
476 static int flac_rewrite_tags(const char *map, size_t map_bytes,
477                 struct taginfo *tags, int fd, __a_unused const char *filename)
478 {
479         int ret;
480         FLAC__Metadata_Chain *chain;
481         FLAC__Metadata_Iterator *iter;
482         FLAC__StreamMetadata *b = NULL;
483         FLAC__bool ok;
484         struct private_flac_afh_data *pfad = para_calloc(sizeof(*pfad));
485
486         pfad->map = map;
487         pfad->map_bytes = map_bytes;
488         pfad->fpos = 0;
489
490         ret = flac_init_meta(pfad, &chain, &iter);
491         if (ret < 0)
492                 goto free_pfad;
493         for (ok = true; ok; ok = FLAC__metadata_iterator_next(iter)) {
494                 b = FLAC__metadata_iterator_get_block(iter);
495                 assert(b);
496                 if (b->type == FLAC__METADATA_TYPE_VORBIS_COMMENT)
497                         break;
498                 b = NULL;
499         }
500         ret = -E_FLAC_REPLACE_COMMENT;
501         if (!b)
502                 goto out;
503         ret = flac_replace_vorbis_comments(chain, b, tags);
504         if (ret < 0)
505                 goto out;
506         ret = flac_write_chain(chain, pfad, fd);
507 out:
508         FLAC__metadata_iterator_delete(iter);
509         FLAC__metadata_chain_delete(chain);
510 free_pfad:
511         free(pfad);
512         return ret;
513 }
514
515 static const char * const flac_suffixes[] = {"flac", NULL};
516
517 /**
518  * The init function of the flac audio format handler.
519  *
520  * \param afh pointer to the struct to initialize
521  */
522 void flac_afh_init(struct audio_format_handler *afh)
523 {
524         afh->get_file_info = flac_get_file_info,
525         afh->suffixes = flac_suffixes;
526         afh->rewrite_tags = flac_rewrite_tags;
527 }