/**
* @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;
}
}
|