/* This file is part of libextractor. Copyright (C) 2002, 2003, 2009, 2012 Vidyut Samanta and Christian Grothoff libextractor 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 3, or (at your option) any later version. libextractor 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 libextractor; see the file COPYING. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /** * @file plugins/ogg_extractor.c * @brief plugin to support OGG files * @author Christian Grothoff */ #include "platform.h" #include "extractor.h" #include /** * Bytes each ogg file must begin with (not used, but we might * choose to add this back in the future to improve performance * for non-ogg files). */ #define OGG_HEADER 0x4f676753 /** * Custom read function for ogg. * * @param ptr where to write the data * @param size number of bytes to read per member * @param nmemb number of members to read * @param datasource the 'struct EXTRACTOR_ExtractContext' * @return 0 on end-of-data, 0 with errno set to indicate read error */ static size_t read_ogg (void *ptr, size_t size, size_t nmemb, void *datasource) { struct EXTRACTOR_ExtractContext *ec = datasource; void *data; ssize_t ret; data = NULL; ret = ec->read (ec->cls, &data, size * nmemb); if (-1 == ret) return 0; if (0 == ret) { errno = 0; return 0; } memcpy (ptr, data, ret); errno = 0; return ret; } /** * Seek to a particular position in the file. * * @param datasource the 'struct EXTRACTOR_ExtractContext' * @param offset where to seek * @param whence how to seek * @return -1 on error, new position on success */ static int seek_ogg (void *datasource, ogg_int64_t offset, int whence) { struct EXTRACTOR_ExtractContext *ec = datasource; int64_t new_position; new_position = ec->seek (ec->cls, (int64_t) offset, whence); return (long) new_position; } /** * Tell ogg where we are in the file * * @param datasource the 'struct EXTRACTOR_ExtractContext' * @return */ static long tell_ogg (void *datasource) { struct EXTRACTOR_ExtractContext *ec = datasource; return (long) ec->seek (ec->cls, 0, SEEK_CUR); } /** * Extract the associated meta data for a given label from vorbis. * * @param vc vorbis comment data * @param label label marking the desired entry * @return NULL on error, otherwise the meta data */ static char * get_comment (vorbis_comment *vc, const char *label) { if (NULL == vc) return NULL; return vorbis_comment_query (vc, label, 0); } /** * Extract meta data from vorbis using the given LE type and value. * * @param t LE meta data type * @param s meta data to add */ #define ADD(t,s) do { if (0 != (ret = ec->proc (ec->cls, "ogg", t, EXTRACTOR_METAFORMAT_UTF8, "text/plain", s, strlen(s)+1))) goto FINISH; } while (0) /** * Extract meta data from vorbis using the given LE type and label. * * @param t LE meta data type * @param d vorbis meta data label */ #define ADDG(t,d) do { m = get_comment (comments, d); if (NULL != m) ADD(t,m); } while (0) /** * Main entry method for the 'application/ogg' extraction plugin. * * @param ec extraction context provided to the plugin */ void EXTRACTOR_ogg_extract_method (struct EXTRACTOR_ExtractContext *ec) { uint64_t fsize; ov_callbacks callbacks; OggVorbis_File vf; vorbis_comment *comments; int ret; const char *m; fsize = ec->get_size (ec->cls); if (fsize < 8) return; callbacks.read_func = &read_ogg; callbacks.seek_func = &seek_ogg; callbacks.close_func = NULL; callbacks.tell_func = &tell_ogg; ret = ov_open_callbacks (ec, &vf, NULL, 0, callbacks); if (0 != ret) { ov_clear (&vf); return; } comments = ov_comment (&vf, -1); if (NULL == comments) { ov_clear (&vf); return; } ADD (EXTRACTOR_METATYPE_MIMETYPE, "application/ogg"); if ((comments->vendor != NULL) && (strlen (comments->vendor) > 0)) ADD (EXTRACTOR_METATYPE_VENDOR, comments->vendor); ADDG (EXTRACTOR_METATYPE_TITLE, "title"); ADDG (EXTRACTOR_METATYPE_ARTIST, "artist"); ADDG (EXTRACTOR_METATYPE_PERFORMER, "performer"); ADDG (EXTRACTOR_METATYPE_ALBUM, "album"); ADDG (EXTRACTOR_METATYPE_TRACK_NUMBER, "tracknumber"); ADDG (EXTRACTOR_METATYPE_DISC_NUMBER, "discnumber"); ADDG (EXTRACTOR_METATYPE_CONTACT_INFORMATION, "contact"); ADDG (EXTRACTOR_METATYPE_GENRE, "genre"); ADDG (EXTRACTOR_METATYPE_CREATION_DATE, "date"); ADDG (EXTRACTOR_METATYPE_COMMENT, ""); ADDG (EXTRACTOR_METATYPE_LOCATION_SUBLOCATION, "location"); ADDG (EXTRACTOR_METATYPE_DESCRIPTION, "description"); ADDG (EXTRACTOR_METATYPE_ISRC, "isrc"); ADDG (EXTRACTOR_METATYPE_ORGANIZATION, "organization"); ADDG (EXTRACTOR_METATYPE_COPYRIGHT, "copyright"); ADDG (EXTRACTOR_METATYPE_LICENSE, "license"); ADDG (EXTRACTOR_METATYPE_SONG_VERSION, "version"); FINISH: ov_clear (&vf); } /* end of ogg_extractor.c */