Source code: org/esau/ptarmigan/impl/filter/VorbisCommentFilter.java
1 /* $Header: /cvsroot/ptarmigan/ptarmigan/src/java/org/esau/ptarmigan/impl/filter/VorbisCommentFilter.java,v 1.2 2002/09/19 03:50:48 reedesau Exp $ */
2
3 package org.esau.ptarmigan.impl.filter;
4
5 import java.io.IOException;
6 import java.text.ParseException;
7
8 import org.xml.sax.SAXException;
9
10 import org.apache.commons.logging.Log;
11 import org.apache.commons.logging.LogFactory;
12
13 import org.esau.ptarmigan.util.MultiMap;
14
15 /**
16 * Extract metadata from an OGG Vorbis native tag format
17 *
18 * Following the three header packets, all packets in a Vorbis I stream
19 * are audio.
20 *
21 * @author Reed Esau
22 * @author Philip Gladstone
23 * @version $Revision: 1.2 $ $Date: 2002/09/19 03:50:48 $
24 */
25 public abstract class VorbisCommentFilter extends BinaryFilter {
26
27 public VorbisCommentFilter() throws SAXException {
28
29 //NOTE: don't declare mime-type in ctor because we might be reading
30 // vorbis tags from FLAC or some other format
31 }
32
33 /** shared with FLAC to read comment packet */
34 int readCommentSubPacket() throws IOException, SAXException, ParseException {
35
36 if (log.isDebugEnabled())
37 log.debug("readCommentSubPacket: counter=" + counter());
38
39 final String local_name = "comments";
40 final String q_name = NS_PREFIX + ":" + local_name;
41
42 startElement(NS_URI, local_name, q_name, EMPTY_ATTRS);
43
44 int total = 0;
45
46 byte[] buf = new byte[2048];
47
48 int bytes_read = readComment(buf); // vendor string
49
50 total += (4+bytes_read);
51
52 write(NS_URI, NS_PREFIX, "vendor", buf, 0, bytes_read, ENCODING);
53
54 int comment_count = readInt32LE();
55 total += 4;
56
57 MultiMap content_map = new MultiMap(); // map of keys, each with a list of values
58
59 for (int i = 0; i < comment_count; i++) {
60 bytes_read = readComment(buf);
61 total += (4+bytes_read);
62
63 int j;
64 for (j = 0; j < bytes_read; j++)
65 if (buf[j] == '=')
66 break;
67 if (j < bytes_read) {
68 String key = new String(buf, 0, j).toLowerCase();
69 String value = new String(buf, j+1, bytes_read-j-1, ENCODING);
70 content_map.put(key, value);
71 }
72 else { // if no key=value, treat as a comment (may be more than one!)
73 write(NS_URI, NS_PREFIX, "user-comment", buf, 0, bytes_read, ENCODING);
74 }
75 }
76
77 // dump the Content in the sequence required by the schema
78 writeContentMap(content_map);
79
80 endElement(NS_URI, local_name, q_name);
81
82 return total;
83 }
84
85 //
86 // internal
87 //
88
89 /**
90 * consume a comment string prefixed by an UNSIGNED length integer (4-bytes)
91 *
92 * @return number of bytes read into buffer for the comment
93 */
94 private int readComment(byte[] buf) throws IOException, ParseException {
95
96 int len = readInt32LE();
97
98 if (len > MAX_COMMENT_SIZE)
99 throw new ParseException("allowable comment size exceeded", 0); //TODO: supply the position
100
101 read(buf, 0, len);
102
103 return len;
104 }
105
106 /** write those items available in content_map as elements in the order prescribed by the schema */
107 private void writeContentMap(MultiMap content_map) throws SAXException {
108
109 final int DEFAULT_LIMIT = 100;
110
111 final String local_name = "content";
112 final String q_name = NS_PREFIX + ":" + local_name;
113
114 startElement(NS_URI, local_name, q_name, EMPTY_ATTRS);
115
116 // Track/Work name
117 writeString(NS_URI, NS_PREFIX, content_map, "title", DEFAULT_LIMIT);
118
119 // The version field may be used to differentiate multiple versions of the same track title in a single collection. (e.g. remix info)
120 writeString(NS_URI, NS_PREFIX, content_map, "version", 1);
121
122 // The collection name to which this track belongs
123 writeString(NS_URI, NS_PREFIX, content_map, "album", DEFAULT_LIMIT);
124
125 // The track number of this piece if part of a specific larger collection or album
126 writeInteger(NS_URI, NS_PREFIX, content_map, "tracknumber", 1);
127
128 // The artist generally considered responsible for the work. In popular music this is usually the performing band or singer. For classical music it would be the composer. For an audio book it would be the author of the original text.
129 writeString(NS_URI, NS_PREFIX, content_map, "artist", DEFAULT_LIMIT);
130
131 // The artist(s) who performed the work. In classical music this would be the conductor, orchestra, soloists. In an audio book it would be the actor who did the reading. In popular music this is typically the same as the ARTIST and is omitted.
132 writeString(NS_URI, NS_PREFIX, content_map, "performer", DEFAULT_LIMIT);
133
134 // Copyright attribution, e.g., '2001 Nobody's Band' or '1999 Jack Moffitt'
135 writeString(NS_URI, NS_PREFIX, content_map, "copyright", DEFAULT_LIMIT);
136
137 // License information, eg, 'All Rights Reserved', 'Any Use Permitted', a URL to a license such as a Creative Commons license ("www.creativecommons.org/blahblah/license.html") or the EFF Open Audio License ('distributed under the terms of the Open Audio License. see http://www.eff.org/IP/Open_licenses/eff_oal.html for details'), etc.
138 writeString(NS_URI, NS_PREFIX, content_map, "license", DEFAULT_LIMIT);
139
140 // Name of the organization producing the track (i.e. the 'record label')
141 writeString(NS_URI, NS_PREFIX, content_map, "organization", DEFAULT_LIMIT);
142
143 // A short text description of the contents
144 writeString(NS_URI, NS_PREFIX, content_map, "description", DEFAULT_LIMIT);
145
146 // A short text indication of music genre
147 writeString(NS_URI, NS_PREFIX, content_map, "genre", DEFAULT_LIMIT);
148
149 // Date the track was recorded
150 writeDate(NS_URI, NS_PREFIX, content_map, "date", DEFAULT_LIMIT);
151
152 // Location where track was recorded
153 writeString(NS_URI, NS_PREFIX, content_map, "location", DEFAULT_LIMIT);
154
155 // Contact information for the creators or distributors of the track. This could be a URL, an email address, the physical address of the producing label.
156 writeString(NS_URI, NS_PREFIX, content_map, "contact", DEFAULT_LIMIT);
157
158 // ISRC number for the track; see the ISRC intro page for more information on ISRC numbers.
159 writeString(NS_URI, NS_PREFIX, content_map, "isrc", DEFAULT_LIMIT);
160
161 writeString(NS_URI, NS_PREFIX, content_map, "replaygain_album_gain", 1);
162 writeString(NS_URI, NS_PREFIX, content_map, "replaygain_album_peak", 1);
163 writeString(NS_URI, NS_PREFIX, content_map, "replaygain_track_gain", 1);
164 writeString(NS_URI, NS_PREFIX, content_map, "replaygain_track_peak", 1);
165
166 endElement(NS_URI, local_name, q_name);
167 }
168
169 //
170 // constants
171 //
172
173 static final String NS_URI = "http://esau.org/ns/ptarmigan/vorbis";
174 static final String NS_PREFIX = "ogg";
175
176 static final int MAX_COMMENT_SIZE = 10000; // arbitrary limit to prevent OOM exceptions
177
178 static final String ENCODING = "UTF-8";
179
180 /**
181 * logging object
182 */
183 static Log log = LogFactory.getLog(VorbisCommentFilter.class);
184 }
185
186 /*
187 PTARMIGAN MODIFIED BSD LICENSE
188
189 Copyright (c) 2002, Reed Esau (reed.esau@pobox.com) All rights reserved.
190
191 Redistribution and use in source and binary forms, with or without
192 modification, are permitted provided that the following conditions are
193 met:
194
195 Redistributions of source code must retain the above copyright notice,
196 this list of conditions and the following disclaimer.
197
198 Redistributions in binary form must reproduce the above copyright notice,
199 this list of conditions and the following disclaimer in the documentation
200 and/or other materials provided with the distribution.
201
202 Neither the name of the Ptarmigan Project
203 (http://ptarmigan.sourceforge.net) nor the names of its contributors may
204 be used to endorse or promote products derived from this software without
205 specific prior written permission.
206
207 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
208 IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
209 THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
210 PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
211 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
212 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
213 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
214 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
215 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
216 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
217 POSSIBILITY OF SUCH DAMAGE.
218 */