ogg_extractor.c (5731B)
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, 87 (int64_t) offset, 88 whence); 89 return (long) new_position; 90 } 91 92 93 /** 94 * Tell ogg where we are in the file 95 * 96 * @param datasource the 'struct EXTRACTOR_ExtractContext' 97 * @return 98 */ 99 static long 100 tell_ogg (void *datasource) 101 { 102 struct EXTRACTOR_ExtractContext *ec = datasource; 103 104 return (long) ec->seek (ec->cls, 105 0, 106 SEEK_CUR); 107 } 108 109 110 /** 111 * Extract the associated meta data for a given label from vorbis. 112 * 113 * @param vc vorbis comment data 114 * @param label label marking the desired entry 115 * @return NULL on error, otherwise the meta data 116 */ 117 static char * 118 get_comment (vorbis_comment *vc, 119 const char *label) 120 { 121 if (NULL == vc) 122 return NULL; 123 return vorbis_comment_query (vc, label, 0); 124 } 125 126 127 /** 128 * Extract meta data from vorbis using the given LE type and value. 129 * 130 * @param t LE meta data type 131 * @param s meta data to add 132 */ 133 #define ADD(t,s) do { if (0 != (ret = ec->proc (ec->cls, "ogg", t, \ 134 EXTRACTOR_METAFORMAT_UTF8, \ 135 "text/plain", s, strlen (s) \ 136 + 1))) goto FINISH; \ 137 } while (0) 138 139 140 /** 141 * Extract meta data from vorbis using the given LE type and label. 142 * 143 * @param t LE meta data type 144 * @param d vorbis meta data label 145 */ 146 #define ADDG(t,d) do { m = get_comment (comments, d); if (NULL != m) ADD (t,m); \ 147 } while (0) 148 149 150 /** 151 * Main entry method for the 'application/ogg' extraction plugin. 152 * 153 * @param ec extraction context provided to the plugin 154 */ 155 void 156 EXTRACTOR_ogg_extract_method (struct EXTRACTOR_ExtractContext *ec) 157 { 158 uint64_t fsize; 159 ov_callbacks callbacks; 160 OggVorbis_File vf; 161 vorbis_comment *comments; 162 int ret; 163 const char *m; 164 165 fsize = ec->get_size (ec->cls); 166 if (fsize < 8) 167 return; 168 169 callbacks.read_func = &read_ogg; 170 callbacks.seek_func = &seek_ogg; 171 callbacks.close_func = NULL; 172 callbacks.tell_func = &tell_ogg; 173 ret = ov_open_callbacks (ec, &vf, NULL, 0, callbacks); 174 if (0 != ret) 175 { 176 ov_clear (&vf); 177 return; 178 } 179 comments = ov_comment (&vf, -1); 180 if (NULL == comments) 181 { 182 ov_clear (&vf); 183 return; 184 } 185 ADD (EXTRACTOR_METATYPE_MIMETYPE, "application/ogg"); 186 if ((comments->vendor != NULL) && (strlen (comments->vendor) > 0)) 187 ADD (EXTRACTOR_METATYPE_VENDOR, comments->vendor); 188 ADDG (EXTRACTOR_METATYPE_TITLE, "title"); 189 ADDG (EXTRACTOR_METATYPE_ARTIST, "artist"); 190 ADDG (EXTRACTOR_METATYPE_PERFORMER, "performer"); 191 ADDG (EXTRACTOR_METATYPE_ALBUM, "album"); 192 ADDG (EXTRACTOR_METATYPE_TRACK_NUMBER, "tracknumber"); 193 ADDG (EXTRACTOR_METATYPE_DISC_NUMBER, "discnumber"); 194 ADDG (EXTRACTOR_METATYPE_CONTACT_INFORMATION, "contact"); 195 ADDG (EXTRACTOR_METATYPE_GENRE, "genre"); 196 ADDG (EXTRACTOR_METATYPE_CREATION_DATE, "date"); 197 ADDG (EXTRACTOR_METATYPE_COMMENT, ""); 198 ADDG (EXTRACTOR_METATYPE_LOCATION_SUBLOCATION, "location"); 199 ADDG (EXTRACTOR_METATYPE_DESCRIPTION, "description"); 200 ADDG (EXTRACTOR_METATYPE_ISRC, "isrc"); 201 ADDG (EXTRACTOR_METATYPE_ORGANIZATION, "organization"); 202 ADDG (EXTRACTOR_METATYPE_COPYRIGHT, "copyright"); 203 ADDG (EXTRACTOR_METATYPE_LICENSE, "license"); 204 ADDG (EXTRACTOR_METATYPE_SONG_VERSION, "version"); 205 FINISH: 206 ov_clear (&vf); 207 } 208 209 210 /* end of ogg_extractor.c */