package org.jaudiotagger.tag.datatype;
import org.jaudiotagger.tag.InvalidDataTypeException;
import org.jaudiotagger.tag.id3.AbstractTagFrameBody;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.ListIterator;
import java.util.logging.Level;
/**
* Represents a data type that supports multiple terminated Strings (there may only be one)
*/
public class MultipleTextEncodedStringNullTerminated extends AbstractDataType
{
/**
* Creates a new ObjectStringSizeTerminated datatype.
*
* @param identifier identifies the frame type
* @param frameBody
*/
public MultipleTextEncodedStringNullTerminated(String identifier, AbstractTagFrameBody frameBody)
{
super(identifier, frameBody);
value = new MultipleTextEncodedStringNullTerminated.Values();
}
public MultipleTextEncodedStringNullTerminated(TextEncodedStringSizeTerminated object)
{
super(object);
value = new MultipleTextEncodedStringNullTerminated.Values();
}
public MultipleTextEncodedStringNullTerminated(MultipleTextEncodedStringNullTerminated object)
{
super(object);
}
public boolean equals(Object obj)
{
return obj instanceof MultipleTextEncodedStringNullTerminated && super.equals(obj);
}
/**
* Returns the size in bytes of this datatype when written to file
*
* @return size of this datatype
*/
public int getSize()
{
return size;
}
/**
* Check the value can be encoded with the specified encoding
* @return
*/
public boolean canBeEncoded()
{
for (ListIterator<String> li = ((Values) value).getList().listIterator(); li.hasNext();)
{
TextEncodedStringNullTerminated next = new TextEncodedStringNullTerminated(identifier, frameBody, li.next());
if (!next.canBeEncoded())
{
return false;
}
}
return true;
}
/**
* Read Null Terminated Strings from the array starting at offset, continue until unable to find any null terminated
* Strings or until reached the end of the array. The offset should be set to byte after the last null terminated
* String found.
*
* @param arr to read the Strings from
* @param offset in the array to start reading from
* @throws InvalidDataTypeException if unable to find any null terminated Strings
*/
public void readByteArray(byte[] arr, int offset) throws InvalidDataTypeException
{
logger.finer("Reading MultipleTextEncodedStringNullTerminated from array from offset:" + offset);
//Continue until unable to read a null terminated String
while (true)
{
try
{
//Read String
TextEncodedStringNullTerminated next = new TextEncodedStringNullTerminated(identifier, frameBody);
next.readByteArray(arr, offset);
if (next.getSize() == 0)
{
break;
}
else
{
//Add to value
((Values) value).add((String) next.getValue());
//Add to size calculation
size += next.getSize();
//Increment Offset to start of next datatype.
offset += next.getSize();
}
}
catch (InvalidDataTypeException idte)
{
break;
}
if (size == 0)
{
logger.warning("No null terminated Strings found");
throw new InvalidDataTypeException("No null terminated Strings found");
}
}
logger.finer("Read MultipleTextEncodedStringNullTerminated:" + value + " size:" + size);
}
/**
* For every String write to bytebuffer
*
* @return bytebuffer that should be written to file to persist this datatype.
*/
public byte[] writeByteArray()
{
logger.finer("Writing MultipleTextEncodedStringNullTerminated");
int localSize = 0;
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
try
{
for (ListIterator<String> li = ((Values) value).getList().listIterator(); li.hasNext();)
{
TextEncodedStringNullTerminated next = new TextEncodedStringNullTerminated(identifier, frameBody, li.next());
buffer.write(next.writeByteArray());
localSize += next.getSize();
}
}
catch (IOException ioe)
{
//This should never happen because the write is internal with the JVM it is not to a file
logger.log(Level.SEVERE, "IOException in MultipleTextEncodedStringNullTerminated when writing byte array", ioe);
throw new RuntimeException(ioe);
}
//Update size member variable
size = localSize;
logger.finer("Written MultipleTextEncodedStringNullTerminated");
return buffer.toByteArray();
}
/**
* This holds the values held by a MultipleTextEncodedData type
*/
public static class Values
{
private List<String> valueList = new ArrayList<String>();
public Values()
{
}
/**
* Add String Data type to the value list
*
* @param value to add to the list
*/
public void add(String value)
{
valueList.add(value);
}
/**
* Return the list of values
*
* @return the list of values
*/
public List<String> getList()
{
return valueList;
}
/**
*
* @return no of values
*/
public int getNumberOfValues()
{
return valueList.size();
}
/**
* Return the list of values as a single string separated by a comma
*
* @return a string representation of the value
*/
public String toString()
{
StringBuffer sb = new StringBuffer();
for (ListIterator<String> li = valueList.listIterator(); li.hasNext();)
{
String next = li.next();
sb.append(next);
if (li.hasNext())
{
sb.append(",");
}
}
return sb.toString();
}
}
}
|