ogg_extractor.c (5677B)
1 /* 2 This file is part of libextractor. 3 Copyright (C) 2002, 2003, 2009, 2012 Vidyut Samanta and Christian Grothoff 4 5 libextractor is free software; you can redistribute it and/or modify 6 it under the terms of the GNU General Public License as published 7 by the Free Software Foundation; either version 3, or (at your 8 option) any later version. 9 10 libextractor is distributed in the hope that it will be useful, but 11 WITHOUT ANY WARRANTY; without even the implied warranty of 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 General Public License for more details. 14 15 You should have received a copy of the GNU General Public License 16 along with libextractor; see the file COPYING. If not, write to the 17 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 18 Boston, MA 02110-1301, USA. 19 */ 20 /** 21 * @file plugins/ogg_extractor.c 22 * @brief plugin to support OGG files 23 * @author Christian Grothoff 24 */ 25 #include "platform.h" 26 #include "extractor.h" 27 #include <vorbis/vorbisfile.h> 28 29 /** 30 * Bytes each ogg file must begin with (not used, but we might 31 * choose to add this back in the future to improve performance 32 * for non-ogg files). 33 */ 34 #define OGG_HEADER 0x4f676753 35 36 37 /** 38 * Custom read function for ogg. 39 * 40 * @param ptr where to write the data 41 * @param size number of bytes to read per member 42 * @param nmemb number of members to read 43 * @param datasource the 'struct EXTRACTOR_ExtractContext' 44 * @return 0 on end-of-data, 0 with errno set to indicate read error 45 */ 46 static size_t 47 read_ogg (void *ptr, size_t size, size_t nmemb, void *datasource) 48 { 49 struct EXTRACTOR_ExtractContext *ec = datasource; 50 void *data; 51 ssize_t ret; 52 53 data = NULL; 54 ret = ec->read (ec->cls, 55 &data, 56 size * nmemb); 57 if (-1 == ret) 58 return 0; 59 if (0 == ret) 60 { 61 errno = 0; 62 return 0; 63 } 64 memcpy (ptr, data, ret); 65 errno = 0; 66 return ret; 67 } 68 69 70 /** 71 * Seek to a particular position in the file. 72 * 73 * @param datasource the 'struct EXTRACTOR_ExtractContext' 74 * @param offset where to seek 75 * @param whence how to seek 76 * @return -1 on error, new position on success 77 */ 78 static int 79 seek_ogg (void *datasource, 80 ogg_int64_t offset, 81 int whence) 82 { 83 struct EXTRACTOR_ExtractContext *ec = datasource; 84 int64_t new_position; 85 86 new_position = ec->seek (ec->cls, (int64_t) offset, whence); 87 return (long) new_position; 88 } 89 90 91 /** 92 * Tell ogg where we are in the file 93 * 94 * @param datasource the 'struct EXTRACTOR_ExtractContext' 95 * @return 96 */ 97 static long 98 tell_ogg (void *datasource) 99 { 100 struct EXTRACTOR_ExtractContext *ec = datasource; 101 102 return (long) ec->seek (ec->cls, 103 0, 104 SEEK_CUR); 105 } 106 107 108 /** 109 * Extract the associated meta data for a given label from vorbis. 110 * 111 * @param vc vorbis comment data 112 * @param label label marking the desired entry 113 * @return NULL on error, otherwise the meta data 114 */ 115 static char * 116 get_comment (vorbis_comment *vc, 117 const char *label) 118 { 119 if (NULL == vc) 120 return NULL; 121 return vorbis_comment_query (vc, label, 0); 122 } 123 124 125 /** 126 * Extract meta data from vorbis using the given LE type and value. 127 * 128 * @param t LE meta data type 129 * @param s meta data to add 130 */ 131 #define ADD(t,s) do { if (0 != (ret = ec->proc (ec->cls, "ogg", t, \ 132 EXTRACTOR_METAFORMAT_UTF8, \ 133 "text/plain", s, strlen (s) \ 134 + 1))) goto FINISH; \ 135 } while (0) 136 137 138 /** 139 * Extract meta data from vorbis using the given LE type and label. 140 * 141 * @param t LE meta data type 142 * @param d vorbis meta data label 143 */ 144 #define ADDG(t,d) do { m = get_comment (comments, d); if (NULL != m) ADD (t,m); \ 145 } while (0) 146 147 148 /** 149 * Main entry method for the 'application/ogg' extraction plugin. 150 * 151 * @param ec extraction context provided to the plugin 152 */ 153 void 154 EXTRACTOR_ogg_extract_method (struct EXTRACTOR_ExtractContext *ec) 155 { 156 uint64_t fsize; 157 ov_callbacks callbacks; 158 OggVorbis_File vf; 159 vorbis_comment *comments; 160 int ret; 161 const char *m; 162 163 fsize = ec->get_size (ec->cls); 164 if (fsize < 8) 165 return; 166 167 callbacks.read_func = &read_ogg; 168 callbacks.seek_func = &seek_ogg; 169 callbacks.close_func = NULL; 170 callbacks.tell_func = &tell_ogg; 171 ret = ov_open_callbacks (ec, &vf, NULL, 0, callbacks); 172 if (0 != ret) 173 { 174 ov_clear (&vf); 175 return; 176 } 177 comments = ov_comment (&vf, -1); 178 if (NULL == comments) 179 { 180 ov_clear (&vf); 181 return; 182 } 183 ADD (EXTRACTOR_METATYPE_MIMETYPE, "application/ogg"); 184 if ((comments->vendor != NULL) && (strlen (comments->vendor) > 0)) 185 ADD (EXTRACTOR_METATYPE_VENDOR, comments->vendor); 186 ADDG (EXTRACTOR_METATYPE_TITLE, "title"); 187 ADDG (EXTRACTOR_METATYPE_ARTIST, "artist"); 188 ADDG (EXTRACTOR_METATYPE_PERFORMER, "performer"); 189 ADDG (EXTRACTOR_METATYPE_ALBUM, "album"); 190 ADDG (EXTRACTOR_METATYPE_TRACK_NUMBER, "tracknumber"); 191 ADDG (EXTRACTOR_METATYPE_DISC_NUMBER, "discnumber"); 192 ADDG (EXTRACTOR_METATYPE_CONTACT_INFORMATION, "contact"); 193 ADDG (EXTRACTOR_METATYPE_GENRE, "genre"); 194 ADDG (EXTRACTOR_METATYPE_CREATION_DATE, "date"); 195 ADDG (EXTRACTOR_METATYPE_COMMENT, ""); 196 ADDG (EXTRACTOR_METATYPE_LOCATION_SUBLOCATION, "location"); 197 ADDG (EXTRACTOR_METATYPE_DESCRIPTION, "description"); 198 ADDG (EXTRACTOR_METATYPE_ISRC, "isrc"); 199 ADDG (EXTRACTOR_METATYPE_ORGANIZATION, "organization"); 200 ADDG (EXTRACTOR_METATYPE_COPYRIGHT, "copyright"); 201 ADDG (EXTRACTOR_METATYPE_LICENSE, "license"); 202 ADDG (EXTRACTOR_METATYPE_SONG_VERSION, "version"); 203 FINISH: 204 ov_clear (&vf); 205 } 206 207 208 /* end of ogg_extractor.c */