diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/aiff.c | 103 | ||||
-rw-r--r-- | src/aiff.h | 40 | ||||
-rw-r--r-- | src/riff.c | 2 | ||||
-rw-r--r-- | src/tag_id3.c | 9 |
4 files changed, 149 insertions, 5 deletions
diff --git a/src/aiff.c b/src/aiff.c new file mode 100644 index 000000000..768e99373 --- /dev/null +++ b/src/aiff.c @@ -0,0 +1,103 @@ +/* + * Copyright (C) 2003-2009 The Music Player Daemon Project + * http://www.musicpd.org + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "aiff.h" + +#include <glib.h> + +#include <stdint.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <unistd.h> +#include <errno.h> +#include <string.h> + +#undef G_LOG_DOMAIN +#define G_LOG_DOMAIN "aiff" + +struct aiff_header { + char id[4]; + uint32_t size; + char format[4]; +}; + +struct aiff_chunk_header { + char id[4]; + uint32_t size; +}; + +size_t +aiff_seek_id3(FILE *file) +{ + int ret; + struct stat st; + struct aiff_header header; + struct aiff_chunk_header chunk; + size_t size; + + /* determine the file size */ + + ret = fstat(fileno(file), &st); + if (ret < 0) { + g_warning("Failed to stat file descriptor: %s", + strerror(errno)); + return 0; + } + + /* seek to the beginning and read the AIFF header */ + + ret = fseek(file, 0, SEEK_SET); + if (ret != 0) { + g_warning("Failed to seek: %s", g_strerror(errno)); + return 0; + } + + size = fread(&header, sizeof(header), 1, file); + if (size != 1 || + memcmp(header.id, "FORM", 4) != 0 || + GUINT32_FROM_BE(header.size) > st.st_size || + memcmp(header.format, "AIFF", 4) != 0) + /* not a AIFF file */ + return 0; + + while (true) { + /* read the chunk header */ + + size = fread(&chunk, sizeof(chunk), 1, file); + if (size != 1) + return 0; + + size = GUINT32_FROM_BE(chunk.size); + if (size % 2 != 0) + /* pad byte */ + ++size; + + if (memcmp(chunk.id, "ID3 ", 4) == 0) + /* found it! */ + return size; + + if ((off_t)size < 0) + /* integer underflow after cast to signed + type */ + return 0; + + ret = fseek(file, size, SEEK_CUR); + if (ret != 0) + return 0; + } +} diff --git a/src/aiff.h b/src/aiff.h new file mode 100644 index 000000000..5e97187f5 --- /dev/null +++ b/src/aiff.h @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2003-2009 The Music Player Daemon Project + * http://www.musicpd.org + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/** \file + * + * A parser for the AIFF file format. + */ + +#ifndef MPD_AIFF_H +#define MPD_AIFF_H + +#include <stdbool.h> +#include <stddef.h> +#include <stdio.h> + +/** + * Seeks the AIFF file to the ID3 chunk. + * + * @return the size of the ID3 chunk on success, or 0 if this is not a + * AIFF file or no ID3 chunk was found + */ +size_t +aiff_seek_id3(FILE *file); + +#endif diff --git a/src/riff.c b/src/riff.c index 9af0a2127..4be96ac06 100644 --- a/src/riff.c +++ b/src/riff.c @@ -86,8 +86,6 @@ riff_seek_id3(FILE *file) /* pad byte */ ++size; - g_debug("chunk='%.4s' size=%zu\n", chunk.id, size); - if (memcmp(chunk.id, "id3 ", 4) == 0) /* found it! */ return size; diff --git a/src/tag_id3.c b/src/tag_id3.c index 7cf82c109..2193f2e7a 100644 --- a/src/tag_id3.c +++ b/src/tag_id3.c @@ -19,6 +19,7 @@ #include "tag_id3.h" #include "tag.h" #include "riff.h" +#include "aiff.h" #include "conf.h" #include <glib.h> @@ -426,7 +427,7 @@ static struct id3_tag *findId3TagFromEnd(FILE * stream) } static struct id3_tag * -tag_id3_riff_load(FILE *file) +tag_id3_riff_aiff_load(FILE *file) { size_t size; void *buffer; @@ -435,9 +436,11 @@ tag_id3_riff_load(FILE *file) size = riff_seek_id3(file); if (size == 0) + size = aiff_seek_id3(file); + if (size == 0) return NULL; - if (size > 65536) + if (size > 256 * 1024) /* too large, don't allocate so much memory */ return NULL; @@ -469,7 +472,7 @@ struct tag *tag_id3_load(const char *file) tag = findId3TagFromBeginning(stream); if (tag == NULL) - tag = tag_id3_riff_load(stream); + tag = tag_id3_riff_aiff_load(stream); if (!tag) tag = findId3TagFromEnd(stream); |