/** * @author : Paul Taylor * @author : Eric Farng * * Version @version:$Id: AbstractTagFrameBody.java 895 2010-04-15 15:21:45Z paultaylor $ * * MusicTag Copyright (C)2003,2004 * * 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, * you can get a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * FragmentBody contains the data for a fragment. * ID3v2 tags have frames bodys. Lyrics3 tags have fields bodys * ID3v1 tags do not have fragments bodys. * Fragment Bodies consist of a number of MP3Objects held in an objectList * Methods are additionally defined here to restrieve and set these objects. * We also specify methods for getting/setting the text encoding of textual * data. * Fragment bodies should not be concerned about their parent fragment. For * example most ID3v2 frames can be applied to ID3v2tags of different versions. * The frame header will need modification based on the frame version but this * should have no effect on the frame body. */ package org.jaudiotagger.tag.id3; import org.jaudiotagger.tag.datatype.AbstractDataType; import org.jaudiotagger.tag.datatype.DataTypes; import org.jaudiotagger.tag.id3.valuepair.TextEncoding; import java.util.ArrayList; import java.util.Iterator; /** * A frame body contains the data content for a frame */ public abstract class AbstractTagFrameBody extends AbstractTagItem { public void createStructure() { } /** * Reference to the header associated with this frame body, a framebody can be created without a header * but one it is associated with a header this should be set. It is principally useful for the framebody to know * its header, because this will specify its tag version and some framebodies behave slighly different * between tag versions. */ private AbstractTagFrame header; /** * List of data types that make up this particular frame body. */ protected ArrayList<AbstractDataType> objectList = new ArrayList<AbstractDataType>(); /** * Return the Text Encoding * * @return the text encoding used by this framebody */ public final byte getTextEncoding() { AbstractDataType o = getObject(DataTypes.OBJ_TEXT_ENCODING); if (o != null) { Long encoding = (Long) (o.getValue()); return encoding.byteValue(); } else { return TextEncoding.ISO_8859_1; } } /** * Set the Text Encoding to use for this frame body * * @param textEncoding to use for this frame body */ public final void setTextEncoding(byte textEncoding) { //Number HashMap actually converts this byte to a long setObjectValue(DataTypes.OBJ_TEXT_ENCODING, textEncoding); } /** * Creates a new framebody, at this point the bodys * ObjectList is setup which defines what datatypes are expected in body */ protected AbstractTagFrameBody() { setupObjectList(); } /** * Copy Constructor for fragment body. Copies all objects in the * Object Iterator with data. * * @param copyObject */ protected AbstractTagFrameBody(AbstractTagFrameBody copyObject) { AbstractDataType newObject; for (int i = 0; i < copyObject.objectList.size(); i++) { newObject = (AbstractDataType) ID3Tags.copyObject(copyObject.objectList.get(i)); newObject.setBody(this); this.objectList.add(newObject); } } /** * @return the text value that the user would expect to see for this framebody type, this should be overrridden * for all framebodies */ public String getUserFriendlyValue() { return toString(); } /** * This method calls <code>toString</code> for all it's objects and appends * them without any newline characters. * * @return brief description string */ public String getBriefDescription() { String str = ""; for (AbstractDataType object : objectList) { if ((object.toString() != null) && (object.toString().length() > 0)) { str += (object.getIdentifier() + "=\"" + object.toString() + "\"; "); } } return str; } /** * This method calls <code>toString</code> for all it's objects and appends * them. It contains new line characters and is more suited for display * purposes * * @return formatted description string */ public final String getLongDescription() { String str = ""; for (AbstractDataType object : objectList) { if ((object.toString() != null) && (object.toString().length() > 0)) { str += (object.getIdentifier() + " = " + object.toString() + "\n"); } } return str; } /** * Sets all objects of identifier type to value defined by <code>obj</code> argument. * * @param identifier <code>MP3Object</code> identifier * @param value new datatype value */ public final void setObjectValue(String identifier, Object value) { AbstractDataType object; Iterator<AbstractDataType> iterator = objectList.listIterator(); while (iterator.hasNext()) { object = iterator.next(); if (object.getIdentifier().equals(identifier)) { object.setValue(value); } } } /** * Returns the value of the datatype with the specified * <code>identifier</code> * * @param identifier * @return the value of the dattype with the specified * <code>identifier</code> */ public final Object getObjectValue(String identifier) { return getObject(identifier).getValue(); } /** * Returns the datatype with the specified * <code>identifier</code> * * @param identifier * @return the datatype with the specified * <code>identifier</code> */ public final AbstractDataType getObject(String identifier) { AbstractDataType object; Iterator<AbstractDataType> iterator = objectList.listIterator(); while (iterator.hasNext()) { object = iterator.next(); if (object.getIdentifier().equals(identifier)) { return object; } } return null; } /** * Returns the size in bytes of this fragmentbody * * @return estimated size in bytes of this datatype */ public int getSize() { int size = 0; AbstractDataType object; Iterator<AbstractDataType> iterator = objectList.listIterator(); while (iterator.hasNext()) { object = iterator.next(); size += object.getSize(); } return size; } /** * Returns true if this instance and its entire DataType * array list is a subset of the argument. This class is a subset if it is * the same class as the argument. * * @param obj datatype to determine subset of * @return true if this instance and its entire datatype array list is a * subset of the argument. */ public boolean isSubsetOf(Object obj) { if (!(obj instanceof AbstractTagFrameBody)) { return false; } ArrayList<AbstractDataType> superset = ((AbstractTagFrameBody) obj).objectList; for (AbstractDataType anObjectList : objectList) { if (anObjectList.getValue() != null) { if (!superset.contains(anObjectList)) { return false; } } } return true; } /** * Returns true if this datatype and its entire DataType array * list equals the argument. This datatype is equal to the argument if they * are the same class. * * @param obj datatype to determine equality of * @return true if this datatype and its entire <code>MP3Object</code> array * list equals the argument. */ public boolean equals(Object obj) { if (!(obj instanceof AbstractTagFrameBody)) { return false; } AbstractTagFrameBody object = (AbstractTagFrameBody) obj; boolean check = this.objectList.equals(object.objectList) && super.equals(obj); return check; } /** * Returns an iterator of the DataType list. * * @return iterator of the DataType list. */ public Iterator iterator() { return objectList.iterator(); } /** * Return brief description of FrameBody * * @return brief description of FrameBody */ public String toString() { return getBriefDescription(); } /** * Create the list of Datatypes that this body * expects in the correct order This method needs to be implemented by concrete subclasses */ protected abstract void setupObjectList(); /** * Get Reference to header * * @return */ public AbstractTagFrame getHeader() { return header; } /** * Set header * * @param header */ public void setHeader(AbstractTagFrame header) { this.header = header; } }