/* * Entagged Audio Tag library * Copyright (c) 2003-2005 Raphaƫl Slinckx <raphael@slinckx.net> * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package org.jaudiotagger.tag.vorbiscomment; import org.jaudiotagger.audio.generic.Utils; import org.jaudiotagger.audio.ogg.util.VorbisHeader; import org.jaudiotagger.tag.TagField; import org.jaudiotagger.tag.TagTextField; import static org.jaudiotagger.tag.vorbiscomment.VorbisCommentFieldKey.*; import java.io.UnsupportedEncodingException; /** * This class represents the name and content of a tag entry in ogg-files. * <br> * * @author @author Raphael Slinckx (KiKiDonK) * @author Christian Laireiter (liree) */ public class VorbisCommentTagField implements TagTextField { /** * If <code>true</code>, the id of the current encapsulated tag field is * specified as a common field. <br> * Example is "ARTIST" which should be interpreted by any application as the * artist of the media content. <br> * Will be set during construction with {@link #checkCommon()}. */ private boolean common; /** * Stores the content of the tag field. <br> */ private String content; /** * Stores the id (name) of the tag field. <br> */ private String id; /** * If id is invalid */ private static final String ERRONEOUS_ID = "ERRONEOUS"; /** * Creates an instance. * * @param raw Raw byte data of the tagfield. * @throws UnsupportedEncodingException If the data doesn't conform "UTF-8" specification. */ public VorbisCommentTagField(byte[] raw) throws UnsupportedEncodingException { String field = new String(raw, "UTF-8"); int i = field.indexOf("="); if (i == -1) { //Beware that ogg ID, must be capitalized and contain no space.. this.id = ERRONEOUS_ID; this.content = field; } else { this.id = field.substring(0, i).toUpperCase(); if (field.length() > i) { this.content = field.substring(i + 1); } else { //We have "XXXXXX=" with nothing after the "=" this.content = ""; } } checkCommon(); } /** * Creates an instance. * * @param fieldId ID (name) of the field. * @param fieldContent Content of the field. */ public VorbisCommentTagField(String fieldId, String fieldContent) { this.id = fieldId.toUpperCase(); this.content = fieldContent; checkCommon(); } /** * This method examines the ID of the current field and modifies * {@link #common}in order to reflect if the tag id is a commonly used one. * <br> */ private void checkCommon() { this.common = id.equals(TITLE.getFieldName()) || id.equals(ALBUM.getFieldName()) || id.equals(ARTIST.getFieldName()) || id.equals(GENRE.getFieldName()) || id.equals(TRACKNUMBER.getFieldName()) || id.equals(DATE.getFieldName()) || id.equals(DESCRIPTION.getFieldName()) || id.equals(COMMENT.getFieldName()); } /** * This method will copy all bytes of <code>src</code> to <code>dst</code> * at the specified location. * * @param src bytes to copy. * @param dst where to copy to. * @param dstOffset at which position of <code>dst</code> the data should be * copied. */ protected void copy(byte[] src, byte[] dst, int dstOffset) { // for (int i = 0; i < src.length; i++) // dst[i + dstOffset] = src[i]; /* * Heared that this method is optimized and does its job very near of * the system. */ System.arraycopy(src, 0, dst, dstOffset, src.length); } /** * @see TagField#copyContent(TagField) */ public void copyContent(TagField field) { if (field instanceof TagTextField) { this.content = ((TagTextField) field).getContent(); } } /** * This method will try to return the byte representation of the given * string after it has been converted to the given encoding. <br> * * @param s The string whose converted bytes should be returned. * @param encoding The encoding type to which the string should be converted. * @return If <code>encoding</code> is supported the byte data of the * given string is returned in that encoding. * @throws UnsupportedEncodingException If the requested encoding is not available. */ protected byte[] getBytes(String s, String encoding) throws UnsupportedEncodingException { return s.getBytes(encoding); } /** * @see TagTextField#getContent() */ public String getContent() { return content; } /** * @see TagTextField#getEncoding() */ public String getEncoding() { return VorbisHeader.CHARSET_UTF_8; } /** * @see TagField#getId() */ public String getId() { return this.id; } /** * @see TagField#getRawContent() */ public byte[] getRawContent() throws UnsupportedEncodingException { byte[] size = new byte[VorbisCommentReader.FIELD_COMMENT_LENGTH_LENGTH]; byte[] idBytes = Utils.getDefaultBytes(this.id, "ISO-8859-1"); byte[] contentBytes = getBytes(this.content, "UTF-8"); byte[] b = new byte[4 + idBytes.length + 1 + contentBytes.length]; int length = idBytes.length + 1 + contentBytes.length; size[3] = (byte) ((length & 0xFF000000) >> 24); size[2] = (byte) ((length & 0x00FF0000) >> 16); size[1] = (byte) ((length & 0x0000FF00) >> 8); size[0] = (byte) (length & 0x000000FF); int offset = 0; copy(size, b, offset); offset += 4; copy(idBytes, b, offset); offset += idBytes.length; b[offset] = (byte) 0x3D; offset++;// "=" copy(contentBytes, b, offset); return b; } /** * @see TagField#isBinary() */ public boolean isBinary() { return false; } /** * @see TagField#isBinary(boolean) */ public void isBinary(boolean b) { if (b) { // Only throw if binary = true requested. throw new UnsupportedOperationException("OggTagFields cannot be changed to binary.\n" + "binary data should be stored elsewhere" + " according to Vorbis_I_spec."); } } /** * @see TagField#isCommon() */ public boolean isCommon() { return common; } /** * @see TagField#isEmpty() */ public boolean isEmpty() { return this.content.equals(""); } /** * @see TagTextField#setContent(String) */ public void setContent(String s) { this.content = s; } /** * @see TagTextField#setEncoding(String) */ public void setEncoding(String s) { if (s == null || !s.equalsIgnoreCase("UTF-8")) { throw new UnsupportedOperationException("The encoding of OggTagFields cannot be " + "changed.(specified to be UTF-8)"); } } public String toString() { return getContent(); } }