/*
* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* Description:
*
*/
package org.jaudiotagger.tag.datatype;
import org.jaudiotagger.tag.InvalidDataTypeException;
import org.jaudiotagger.tag.id3.AbstractTagFrameBody;
import java.util.ArrayList;
import java.util.List;
/**
* Represents a list of {@link Cloneable}(!!) {@link AbstractDataType}s, continuing until the end of the buffer.
*
* @author <a href="mailto:hs@tagtraum.com">Hendrik Schreiber</a>
* @version $Id:$
*/
public abstract class AbstractDataTypeList<T extends AbstractDataType> extends AbstractDataType
{
public AbstractDataTypeList(final String identifier, final AbstractTagFrameBody frameBody)
{
super(identifier, frameBody);
setValue(new ArrayList<T>());
}
/**
* Copy constructor.
* By convention, subclasses <em>must</em> implement a constructor, accepting an argument of their own class type
* and call this constructor for {@link org.jaudiotagger.tag.id3.ID3Tags#copyObject(Object)} to work.
* A parametrized {@code AbstractDataTypeList} is not sufficient.
*
* @param copy instance
*/
protected AbstractDataTypeList(final AbstractDataTypeList<T> copy)
{
super(copy);
}
public List<T> getValue()
{
return (List<T>)super.getValue();
}
public void setValue(final List<T> list)
{
super.setValue(list == null ? new ArrayList<T>() : new ArrayList<T>(list));
}
/**
* Return the size in byte of this datatype list.
*
* @return the size in bytes
*/
public int getSize()
{
int size = 0;
for (final T t : getValue()) {
size+=t.getSize();
}
return size;
}
/**
* Reads list of {@link EventTimingCode}s from buffer starting at the given offset.
*
* @param buffer buffer
* @param offset initial offset into the buffer
* @throws NullPointerException
* @throws IndexOutOfBoundsException
*/
public void readByteArray(final byte[] buffer, final int offset) throws InvalidDataTypeException
{
if (buffer == null)
{
throw new NullPointerException("Byte array is null");
}
if (offset < 0)
{
throw new IndexOutOfBoundsException("Offset to byte array is out of bounds: offset = " + offset + ", array.length = " + buffer.length);
}
// no events
if (offset >= buffer.length)
{
getValue().clear();
return;
}
for (int currentOffset = offset; currentOffset<buffer.length;) {
final T data = createListElement();
data.readByteArray(buffer, currentOffset);
data.setBody(frameBody);
getValue().add(data);
currentOffset+=data.getSize();
}
}
/**
* Factory method that creates new elements for this list.
* Called from {@link #readByteArray(byte[], int)}.
*
* @return new list element
*/
protected abstract T createListElement();
/**
* Write contents to a byte array.
*
* @return a byte array that that contains the data that should be persisted to file
*/
public byte[] writeByteArray()
{
logger.config("Writing DataTypeList " + this.getIdentifier());
final byte[] buffer = new byte[getSize()];
int offset = 0;
for (final AbstractDataType data : getValue()) {
final byte[] bytes = data.writeByteArray();
System.arraycopy(bytes, 0, buffer, offset, bytes.length);
offset+=bytes.length;
}
return buffer;
}
@Override
public int hashCode() {
return getValue() != null ? getValue().hashCode() : 0;
}
@Override
public String toString() {
return getValue() != null ? getValue().toString() : "{}";
}
}