1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package entagged.audioformats.asf.data;
20
21 import java.io.ByteArrayOutputStream;
22 import java.math.BigInteger;
23 import java.util.ArrayList;
24 import java.util.Arrays;
25 import java.util.Collection;
26 import java.util.HashMap;
27 import java.util.Iterator;
28
29 import entagged.audioformats.Tag;
30 import entagged.audioformats.asf.util.Utils;
31
32 /***
33 * This structure represents the data of a chunk, wich contains extended content
34 * description. <br>
35 * These properties are simply represented by
36 * {@link entagged.audioformats.asf.data.ContentDescriptor}
37 *
38 * @author Christian Laireiter
39 */
40 public class ExtendedContentDescription extends Chunk {
41
42 /***
43 * Contains the properties. <br>
44 */
45 private final ArrayList descriptors;
46
47 /***
48 * This map stores the ids (names) of inserted content descriptors. <br>
49 * If {@link #getDescriptor(String)}is called this field will be filled if
50 * <code>null</code>. Any modification of the contents of this object
51 * will set this field to <code>null</code>.
52 */
53 private HashMap indexMap = null;
54
55 /***
56 * Creates an instance.
57 *
58 */
59 public ExtendedContentDescription() {
60 this(0, BigInteger.valueOf(0));
61 }
62
63 /***
64 * Creates an instance.
65 *
66 * @param pos
67 * Position of header object within file or stream.
68 * @param chunkLen
69 * Length of the represented chunck.
70 */
71 public ExtendedContentDescription(long pos, BigInteger chunkLen) {
72 super(GUID.GUID_EXTENDED_CONTENT_DESCRIPTION, pos, chunkLen);
73 this.descriptors = new ArrayList();
74 }
75
76 /***
77 * This method inserts the given ContentDescriptor.
78 *
79 * @param toAdd
80 * ContentDescriptor to insert.
81 */
82 public void addDescriptor(ContentDescriptor toAdd) {
83 assert toAdd != null : "Argument must not be null.";
84 if (getDescriptor(toAdd.getName()) != null) {
85 throw new RuntimeException(toAdd.getName() + " is already present");
86 }
87 this.descriptors.add(toAdd);
88 this.indexMap.put(toAdd.getName(), new Integer(descriptors.size() - 1));
89 }
90
91 /***
92 * This method adds or replaces an existing content descriptor.
93 *
94 * @param descriptor
95 * Descriptor to be added or replaced.
96 */
97 public void addOrReplace(ContentDescriptor descriptor) {
98 assert descriptor != null : "Argument must not be null";
99 if (getDescriptor(descriptor.getName()) != null) {
100
101
102
103 remove(descriptor.getName());
104 }
105 addDescriptor(descriptor);
106 }
107
108 /***
109 * Returns the album entered in the content descriptor chunk.
110 *
111 * @return Album, <code>""</code> if not defined.
112 */
113 public String getAlbum() {
114 ContentDescriptor result = getDescriptor(ContentDescriptor.ID_ALBUM);
115 if (result == null)
116 return "";
117
118 return result.getString();
119 }
120
121 /***
122 * Returns the "WM/AlbumArtist" entered in the extended content description.
123 *
124 * @return Title, <code>""</code> if not defined.
125 */
126 public String getArtist() {
127 ContentDescriptor result = getDescriptor(ContentDescriptor.ID_ARTIST);
128 if (result == null)
129 return "";
130 return result.getString();
131 }
132
133 /***
134 * This method creates a byte array which can be written to asf files.
135 *
136 * @return asf file representation of the current object.
137 */
138 public byte[] getBytes() {
139 ByteArrayOutputStream result = new ByteArrayOutputStream();
140 try {
141 ByteArrayOutputStream content = new ByteArrayOutputStream();
142
143 content.write(Utils.getBytes(this.descriptors.size(), 2));
144 Iterator it = this.descriptors.iterator();
145 while (it.hasNext()) {
146 ContentDescriptor current = (ContentDescriptor) it.next();
147 content.write(current.getBytes());
148 }
149 byte[] contentBytes = content.toByteArray();
150
151 result.write(GUID.GUID_EXTENDED_CONTENT_DESCRIPTION.getBytes());
152
153 result.write(Utils.getBytes(contentBytes.length + 24, 8));
154
155 result.write(contentBytes);
156 } catch (Exception e) {
157 e.printStackTrace();
158 }
159 return result.toByteArray();
160 }
161
162 /***
163 * Returns a previously inserted content descriptor.
164 *
165 * @param name
166 * name of the content descriptor.
167 * @return <code>null</code> if not present.
168 */
169 public ContentDescriptor getDescriptor(String name) {
170 if (this.indexMap == null) {
171 this.indexMap = new HashMap();
172 for (int i = 0; i < descriptors.size(); i++) {
173 ContentDescriptor current = (ContentDescriptor) descriptors
174 .get(i);
175 indexMap.put(current.getName(), new Integer(i));
176 }
177 }
178 Integer pos = (Integer) indexMap.get(name);
179 if (pos != null) {
180 return (ContentDescriptor) descriptors.get(pos.intValue());
181 }
182 return null;
183 }
184
185 /***
186 * @return Returns the descriptorCount.
187 */
188 public long getDescriptorCount() {
189 return descriptors.size();
190 }
191
192 /***
193 * Returns a collection of all {@link ContentDescriptor}objects stored in
194 * this extended content description.
195 *
196 * @return An enumeration of {@link ContentDescriptor}objects.
197 */
198 public Collection getDescriptors() {
199 return new ArrayList(this.descriptors);
200 }
201
202 /***
203 * Returns the Genre entered in the content descriptor chunk.
204 *
205 * @return Genre, <code>""</code> if not defined.
206 */
207 public String getGenre() {
208 String result = null;
209 ContentDescriptor prop = getDescriptor(ContentDescriptor.ID_GENRE);
210 if (prop == null) {
211 prop = getDescriptor(ContentDescriptor.ID_GENREID);
212 if (prop == null)
213 result = "";
214 else {
215 result = prop.getString();
216 if (result.startsWith("(") && result.endsWith(")")) {
217 result = result.substring(1, result.length() - 1);
218 try {
219 int genreNum = Integer.parseInt(result);
220 if (genreNum >= 0
221 && genreNum < Tag.DEFAULT_GENRES.length) {
222 result = Tag.DEFAULT_GENRES[genreNum];
223 }
224 } catch (NumberFormatException e) {
225
226 }
227 }
228 }
229 } else {
230 result = prop.getString();
231 }
232 return result;
233 }
234
235 /***
236 * Returns the Track entered in the content descriptor chunk.
237 *
238 * @return Track, <code>""</code> if not defined.
239 */
240 public String getTrack() {
241 ContentDescriptor result = getDescriptor(ContentDescriptor.ID_TRACKNUMBER);
242 if (result == null)
243 return "";
244
245 return result.getString();
246 }
247
248 /***
249 * Returns the Year entered in the extended content descripion.
250 *
251 * @return Year, <code>""</code> if not defined.
252 */
253 public String getYear() {
254 ContentDescriptor result = getDescriptor(ContentDescriptor.ID_YEAR);
255 if (result == null)
256 return "";
257
258 return result.getString();
259 }
260
261 /***
262 * This method creates a String containing the tag elements an their values
263 * for printing. <br>
264 *
265 * @return nice string.
266 */
267 public String prettyPrint() {
268 StringBuffer result = new StringBuffer(super.prettyPrint());
269 result.insert(0, "\nExtended Content Description:\n");
270 ContentDescriptor[] list = (ContentDescriptor[]) descriptors
271 .toArray(new ContentDescriptor[descriptors.size()]);
272 Arrays.sort(list);
273 for (int i = 0; i < list.length; i++) {
274 result.append(" ");
275 result.append(list[i]);
276 result.append(Utils.LINE_SEPARATOR);
277 }
278 return result.toString();
279 }
280
281 /***
282 * This method removes the content descriptor with the given name. <br>
283 *
284 * @param id
285 * The id (name) of the descriptor which should be removed.
286 * @return The descriptor which is removed. If not present <code>null</code>.
287 */
288 public ContentDescriptor remove(String id) {
289 ContentDescriptor result = getDescriptor(id);
290 if (result != null) {
291 descriptors.remove(result);
292 }
293 this.indexMap = null;
294 return result;
295 }
296 }