package org.jaudiotagger.tag.asf;
import org.jaudiotagger.audio.asf.data.AsfHeader;
import org.jaudiotagger.audio.generic.AbstractTag;
import org.jaudiotagger.logging.ErrorMessage;
import org.jaudiotagger.tag.*;
import org.jaudiotagger.tag.images.Artwork;
import org.jaudiotagger.tag.images.ArtworkFactory;
import org.jaudiotagger.tag.mp4.Mp4FieldKey;
import org.jaudiotagger.tag.reference.PictureTypes;
import java.io.UnsupportedEncodingException;
import java.util.*;
/**
* Tag implementation for ASF.<br>
*
* @author Christian Laireiter
*/
public final class AsfTag extends AbstractTag
{
/**
* This iterator is used to iterator an {@link Iterator} with
* {@link TagField} objects and returns them by casting to
* {@link AsfTagField}.<br>
*
* @author Christian Laireiter
*/
private static class AsfFieldIterator implements Iterator<AsfTagField>
{
/**
* source iterator.
*/
private final Iterator<TagField> fieldIterator;
/**
* Creates an isntance.
*
* @param iterator iterator to read from.
*/
public AsfFieldIterator(final Iterator<TagField> iterator)
{
assert iterator != null;
this.fieldIterator = iterator;
}
/**
* {@inheritDoc}
*/
public boolean hasNext()
{
return this.fieldIterator.hasNext();
}
/**
* {@inheritDoc}
*/
public AsfTagField next()
{
return (AsfTagField) this.fieldIterator.next();
}
/**
* {@inheritDoc}
*/
public void remove()
{
this.fieldIterator.remove();
}
}
/**
* Stores a list of field keys, which identify common fields.<br>
*/
public final static Set<AsfFieldKey> COMMON_FIELDS;
/**
* This map contains the mapping from {@link org.jaudiotagger.tag.FieldKey} to
* {@link AsfFieldKey}.
*/
private static final EnumMap<FieldKey, AsfFieldKey> tagFieldToAsfField;
// Mapping from generic key to asf key
static
{
tagFieldToAsfField = new EnumMap<FieldKey, AsfFieldKey>(FieldKey.class);
tagFieldToAsfField.put(FieldKey.ALBUM, AsfFieldKey.ALBUM);
tagFieldToAsfField.put(FieldKey.ALBUM_ARTIST, AsfFieldKey.ALBUM_ARTIST);
tagFieldToAsfField.put(FieldKey.ALBUM_ARTIST_SORT, AsfFieldKey.ALBUM_ARTIST_SORT);
tagFieldToAsfField.put(FieldKey.ALBUM_SORT, AsfFieldKey.ALBUM_SORT);
tagFieldToAsfField.put(FieldKey.AMAZON_ID, AsfFieldKey.AMAZON_ID);
tagFieldToAsfField.put(FieldKey.ARTIST, AsfFieldKey.AUTHOR);
tagFieldToAsfField.put(FieldKey.ARTIST_SORT, AsfFieldKey.ARTIST_SORT);
tagFieldToAsfField.put(FieldKey.ARTISTS, AsfFieldKey.ARTISTS);
tagFieldToAsfField.put(FieldKey.BARCODE, AsfFieldKey.BARCODE);
tagFieldToAsfField.put(FieldKey.BPM, AsfFieldKey.BPM);
tagFieldToAsfField.put(FieldKey.CATALOG_NO, AsfFieldKey.CATALOG_NO);
tagFieldToAsfField.put(FieldKey.COMMENT, AsfFieldKey.DESCRIPTION);
tagFieldToAsfField.put(FieldKey.COMPOSER, AsfFieldKey.COMPOSER);
tagFieldToAsfField.put(FieldKey.COMPOSER_SORT, AsfFieldKey.COMPOSER_SORT);
tagFieldToAsfField.put(FieldKey.CONDUCTOR, AsfFieldKey.CONDUCTOR);
tagFieldToAsfField.put(FieldKey.COVER_ART, AsfFieldKey.COVER_ART);
tagFieldToAsfField.put(FieldKey.CUSTOM1, AsfFieldKey.CUSTOM1);
tagFieldToAsfField.put(FieldKey.CUSTOM2, AsfFieldKey.CUSTOM2);
tagFieldToAsfField.put(FieldKey.CUSTOM3, AsfFieldKey.CUSTOM3);
tagFieldToAsfField.put(FieldKey.CUSTOM4, AsfFieldKey.CUSTOM4);
tagFieldToAsfField.put(FieldKey.CUSTOM5, AsfFieldKey.CUSTOM5);
tagFieldToAsfField.put(FieldKey.DISC_NO, AsfFieldKey.DISC_NO);
tagFieldToAsfField.put(FieldKey.DISC_TOTAL, AsfFieldKey.DISC_TOTAL);
tagFieldToAsfField.put(FieldKey.ENCODER, AsfFieldKey.ENCODER);
tagFieldToAsfField.put(FieldKey.FBPM, AsfFieldKey.FBPM);
tagFieldToAsfField.put(FieldKey.GENRE, AsfFieldKey.GENRE);
tagFieldToAsfField.put(FieldKey.GROUPING, AsfFieldKey.GROUPING);
tagFieldToAsfField.put(FieldKey.ISRC, AsfFieldKey.ISRC);
tagFieldToAsfField.put(FieldKey.IS_COMPILATION, AsfFieldKey.IS_COMPILATION);
tagFieldToAsfField.put(FieldKey.KEY, AsfFieldKey.INITIAL_KEY);
tagFieldToAsfField.put(FieldKey.LANGUAGE, AsfFieldKey.LANGUAGE);
tagFieldToAsfField.put(FieldKey.LYRICIST, AsfFieldKey.LYRICIST);
tagFieldToAsfField.put(FieldKey.LYRICS, AsfFieldKey.LYRICS);
tagFieldToAsfField.put(FieldKey.MEDIA, AsfFieldKey.MEDIA);
tagFieldToAsfField.put(FieldKey.MOOD, AsfFieldKey.MOOD);
tagFieldToAsfField.put(FieldKey.MUSICBRAINZ_ARTISTID, AsfFieldKey.MUSICBRAINZ_ARTISTID);
tagFieldToAsfField.put(FieldKey.MUSICBRAINZ_DISC_ID, AsfFieldKey.MUSICBRAINZ_DISC_ID);
tagFieldToAsfField.put(FieldKey.MUSICBRAINZ_ORIGINAL_RELEASE_ID, AsfFieldKey.MUSICBRAINZ_ORIGINAL_RELEASEID);
tagFieldToAsfField.put(FieldKey.MUSICBRAINZ_RELEASEARTISTID, AsfFieldKey.MUSICBRAINZ_RELEASEARTISTID);
tagFieldToAsfField.put(FieldKey.MUSICBRAINZ_RELEASEID, AsfFieldKey.MUSICBRAINZ_RELEASEID);
tagFieldToAsfField.put(FieldKey.MUSICBRAINZ_RELEASE_COUNTRY, AsfFieldKey.MUSICBRAINZ_RELEASE_COUNTRY);
tagFieldToAsfField.put(FieldKey.MUSICBRAINZ_RELEASE_GROUP_ID, AsfFieldKey.MUSICBRAINZ_RELEASEGROUPID);
tagFieldToAsfField.put(FieldKey.MUSICBRAINZ_RELEASE_STATUS, AsfFieldKey.MUSICBRAINZ_RELEASE_STATUS);
tagFieldToAsfField.put(FieldKey.MUSICBRAINZ_RELEASE_TYPE, AsfFieldKey.MUSICBRAINZ_RELEASE_TYPE);
tagFieldToAsfField.put(FieldKey.MUSICBRAINZ_TRACK_ID, AsfFieldKey.MUSICBRAINZ_TRACK_ID);
tagFieldToAsfField.put(FieldKey.MUSICBRAINZ_WORK_ID, AsfFieldKey.MUSICBRAINZ_WORKID);
tagFieldToAsfField.put(FieldKey.MUSICIP_ID, AsfFieldKey.MUSICIP_ID);
tagFieldToAsfField.put(FieldKey.OCCASION, AsfFieldKey.OCCASION);
tagFieldToAsfField.put(FieldKey.ORIGINAL_ARTIST, AsfFieldKey.ORIGINAL_ARTIST);
tagFieldToAsfField.put(FieldKey.ORIGINAL_ALBUM, AsfFieldKey.ORIGINAL_ALBUM);
tagFieldToAsfField.put(FieldKey.ORIGINAL_LYRICIST, AsfFieldKey.ORIGINAL_LYRICIST);
tagFieldToAsfField.put(FieldKey.ORIGINAL_YEAR, AsfFieldKey.ORIGINAL_YEAR);
tagFieldToAsfField.put(FieldKey.RATING, AsfFieldKey.USER_RATING);
tagFieldToAsfField.put(FieldKey.RECORD_LABEL, AsfFieldKey.RECORD_LABEL);
tagFieldToAsfField.put(FieldKey.QUALITY, AsfFieldKey.QUALITY);
tagFieldToAsfField.put(FieldKey.REMIXER, AsfFieldKey.REMIXER);
tagFieldToAsfField.put(FieldKey.SCRIPT, AsfFieldKey.SCRIPT);
tagFieldToAsfField.put(FieldKey.TAGS, AsfFieldKey.TAGS);
tagFieldToAsfField.put(FieldKey.TEMPO, AsfFieldKey.TEMPO);
tagFieldToAsfField.put(FieldKey.TITLE, AsfFieldKey.TITLE);
tagFieldToAsfField.put(FieldKey.TITLE_SORT, AsfFieldKey.TITLE_SORT);
tagFieldToAsfField.put(FieldKey.TRACK, AsfFieldKey.TRACK);
tagFieldToAsfField.put(FieldKey.TRACK_TOTAL, AsfFieldKey.TRACK_TOTAL);
tagFieldToAsfField.put(FieldKey.URL_DISCOGS_ARTIST_SITE, AsfFieldKey.URL_DISCOGS_ARTIST_SITE);
tagFieldToAsfField.put(FieldKey.URL_DISCOGS_RELEASE_SITE, AsfFieldKey.URL_DISCOGS_RELEASE_SITE);
tagFieldToAsfField.put(FieldKey.URL_LYRICS_SITE, AsfFieldKey.URL_LYRICS_SITE);
tagFieldToAsfField.put(FieldKey.URL_OFFICIAL_ARTIST_SITE, AsfFieldKey.URL_OFFICIAL_ARTIST_SITE);
tagFieldToAsfField.put(FieldKey.URL_OFFICIAL_RELEASE_SITE, AsfFieldKey.URL_OFFICIAL_RELEASE_SITE);
tagFieldToAsfField.put(FieldKey.URL_WIKIPEDIA_ARTIST_SITE, AsfFieldKey.URL_WIKIPEDIA_ARTIST_SITE);
tagFieldToAsfField.put(FieldKey.URL_WIKIPEDIA_RELEASE_SITE, AsfFieldKey.URL_WIKIPEDIA_RELEASE_SITE);
tagFieldToAsfField.put(FieldKey.YEAR, AsfFieldKey.YEAR);
tagFieldToAsfField.put(FieldKey.ENGINEER, AsfFieldKey.ENGINEER);
tagFieldToAsfField.put(FieldKey.PRODUCER, AsfFieldKey.PRODUCER);
tagFieldToAsfField.put(FieldKey.DJMIXER, AsfFieldKey.DJMIXER);
tagFieldToAsfField.put(FieldKey.MIXER, AsfFieldKey.MIXER);
tagFieldToAsfField.put(FieldKey.ARRANGER, AsfFieldKey.ARRANGER);
tagFieldToAsfField.put(FieldKey.ACOUSTID_FINGERPRINT, AsfFieldKey.ACOUSTID_FINGERPRINT);
tagFieldToAsfField.put(FieldKey.ACOUSTID_ID, AsfFieldKey.ACOUSTID_ID);
tagFieldToAsfField.put(FieldKey.COUNTRY, AsfFieldKey.COUNTRY);
}
static
{
COMMON_FIELDS = new HashSet<AsfFieldKey>();
COMMON_FIELDS.add(AsfFieldKey.ALBUM);
COMMON_FIELDS.add(AsfFieldKey.AUTHOR);
COMMON_FIELDS.add(AsfFieldKey.DESCRIPTION);
COMMON_FIELDS.add(AsfFieldKey.GENRE);
COMMON_FIELDS.add(AsfFieldKey.TITLE);
COMMON_FIELDS.add(AsfFieldKey.TRACK);
COMMON_FIELDS.add(AsfFieldKey.YEAR);
}
/**
* @see #isCopyingFields()
*/
private final boolean copyFields;
/**
* Creates an empty instance.
*/
public AsfTag()
{
this(false);
}
/**
* Creates an instance and sets the field conversion property.<br>
*
* @param copy look at {@link #isCopyingFields()}.
*/
public AsfTag(final boolean copy)
{
super();
this.copyFields = copy;
}
/**
* Creates an instance and copies the fields of the source into the own
* structure.<br>
*
* @param source source to read tag fields from.
* @param copy look at {@link #isCopyingFields()}.
* @throws UnsupportedEncodingException {@link TagField#getRawContent()} which may be called
*/
public AsfTag(final Tag source, final boolean copy) throws UnsupportedEncodingException
{
this(copy);
copyFrom(source);
}
/**
* {@inheritDoc}
*/
@Override
// TODO introduce copy idea to all formats
public void addField(final TagField field)
{
if (isValidField(field))
{
if (AsfFieldKey.isMultiValued(field.getId()))
{
super.addField(copyFrom(field));
}
else
{
super.setField(copyFrom(field));
}
}
}
/**
* Creates a field for copyright and adds it.<br>
*
* @param copyRight copyright content
*/
public void addCopyright(final String copyRight)
{
addField(createCopyrightField(copyRight));
}
/**
* Creates a field for rating and adds it.<br>
*
* @param rating rating.
*/
public void addRating(final String rating)
{
addField(createRatingField(rating));
}
/**
* This method copies tag fields from the source.<br>
*
* @param source source to read tag fields from.
*/
private void copyFrom(final Tag source)
{
final Iterator<TagField> fieldIterator = source.getFields();
// iterate over all fields
while (fieldIterator.hasNext())
{
final TagField copy = copyFrom(fieldIterator.next());
if (copy != null)
{
super.addField(copy);
}
}
}
/**
* If {@link #isCopyingFields()} is <code>true</code>, Creates a copy of
* <code>source</code>, if its not empty-<br>
* However, plain {@link TagField} objects can only be transformed into
* binary fields using their {@link TagField#getRawContent()} method.<br>
*
* @param source source field to copy.
* @return A copy, which is as close to the source as possible, or
* <code>null</code> if the field is empty (empty byte[] or blank
* string}.
*/
private TagField copyFrom(final TagField source)
{
TagField result;
if (isCopyingFields())
{
if (source instanceof AsfTagField)
{
try
{
result = (TagField) ((AsfTagField) source).clone();
}
catch (CloneNotSupportedException e)
{
result = new AsfTagField(((AsfTagField) source).getDescriptor());
}
}
else if (source instanceof TagTextField)
{
final String content = ((TagTextField) source).getContent();
result = new AsfTagTextField(source.getId(), content);
}
else
{
throw new RuntimeException("Unknown Asf Tag Field class:" // NOPMD
// by
// Christian
// Laireiter
// on
// 5/9/09
// 5:44
// PM
+ source.getClass());
}
}
else
{
result = source;
}
return result;
}
/**
* Creates an {@link AsfTagCoverField} from given artwork
*
* @param artwork artwork to create a ASF field from.
* @return ASF field capable of storing artwork.
*/
public AsfTagCoverField createField(final Artwork artwork)
{
return new AsfTagCoverField(artwork.getBinaryData(), artwork.getPictureType(), artwork.getDescription(), artwork.getMimeType());
}
/**
* Create artwork field
*
* @param data raw image data
* @return creates a default ASF picture field with default
* {@linkplain PictureTypes#DEFAULT_ID picture type}.
*/
public AsfTagCoverField createArtworkField(final byte[] data)
{
return new AsfTagCoverField(data, PictureTypes.DEFAULT_ID, null, null);
}
/**
* Creates a field for storing the copyright.<br>
*
* @param content Copyright value.
* @return {@link AsfTagTextField}
*/
public AsfTagTextField createCopyrightField(final String content)
{
return new AsfTagTextField(AsfFieldKey.COPYRIGHT, content);
}
/**
* Creates a field for storing the copyright.<br>
*
* @param content Rating value.
* @return {@link AsfTagTextField}
*/
public AsfTagTextField createRatingField(final String content)
{
return new AsfTagTextField(AsfFieldKey.RATING, content);
}
/**
* Create tag text field using ASF key
* <p/>
* Uses the correct subclass for the key.<br>
*
* @param asfFieldKey field key to create field for.
* @param value string value for the created field.
* @return text field with given content.
*/
public AsfTagTextField createField(final AsfFieldKey asfFieldKey, final String value)
{
if (value == null)
{
throw new IllegalArgumentException(ErrorMessage.GENERAL_INVALID_NULL_ARGUMENT.getMsg());
}
if (asfFieldKey == null)
{
throw new IllegalArgumentException(ErrorMessage.GENERAL_INVALID_NULL_ARGUMENT.getMsg());
}
switch (asfFieldKey)
{
case COVER_ART:
throw new UnsupportedOperationException("Cover Art cannot be created using this method");
case BANNER_IMAGE:
throw new UnsupportedOperationException("Banner Image cannot be created using this method");
default:
return new AsfTagTextField(asfFieldKey.getFieldName(), value);
}
}
/**
* {@inheritDoc}
*/
@Override
public AsfTagTextField createField(final FieldKey genericKey, final String value) throws KeyNotFoundException, FieldDataInvalidException
{
if (value == null)
{
throw new IllegalArgumentException(ErrorMessage.GENERAL_INVALID_NULL_ARGUMENT.getMsg());
}
if (genericKey == null)
{
throw new IllegalArgumentException(ErrorMessage.GENERAL_INVALID_NULL_ARGUMENT.getMsg());
}
final AsfFieldKey asfFieldKey = tagFieldToAsfField.get(genericKey);
if (asfFieldKey == null)
{
throw new KeyNotFoundException("No ASF fieldkey for " + genericKey.toString());
}
return createField(asfFieldKey, value);
}
/**
* Removes all fields which are stored to the provided field key.
*
* @param fieldKey fields to remove.
*/
public void deleteField(final AsfFieldKey fieldKey)
{
super.deleteField(fieldKey.getFieldName());
}
/**
* {@inheritDoc}
*/
@Override
public void deleteField(final FieldKey fieldKey) throws KeyNotFoundException
{
if (fieldKey == null)
{
throw new KeyNotFoundException();
}
super.deleteField(tagFieldToAsfField.get(fieldKey).getFieldName());
}
/**
* {@inheritDoc}
*/
@Override
public List<TagField> getFields(final FieldKey fieldKey) throws KeyNotFoundException
{
if (fieldKey == null)
{
throw new KeyNotFoundException();
}
return super.getFields(tagFieldToAsfField.get(fieldKey).getFieldName());
}
/**
* @return
*/
public List<Artwork> getArtworkList()
{
final List<TagField> coverartList = getFields(FieldKey.COVER_ART);
final List<Artwork> artworkList = new ArrayList<Artwork>(coverartList.size());
for (final TagField next : coverartList)
{
final AsfTagCoverField coverArt = (AsfTagCoverField) next;
final Artwork artwork = ArtworkFactory.getNew();
artwork.setBinaryData(coverArt.getRawImageData());
artwork.setMimeType(coverArt.getMimeType());
artwork.setDescription(coverArt.getDescription());
artwork.setPictureType(coverArt.getPictureType());
artworkList.add(artwork);
}
return artworkList;
}
/**
* This method iterates through all stored fields.<br>
* This method can only be used if this class has been created with field
* conversion turned on.
*
* @return Iterator for iterating through ASF fields.
*/
public Iterator<AsfTagField> getAsfFields()
{
if (!isCopyingFields())
{
throw new IllegalStateException("Since the field conversion is not enabled, this method cannot be executed");
}
return new AsfFieldIterator(getFields());
}
/**
* Returns a list of stored copyrights.
*
* @return list of stored copyrights.
*/
public List<TagField> getCopyright()
{
return getFields(AsfFieldKey.COPYRIGHT.getFieldName());
}
/**
* {@inheritDoc}
*/
@Override
public String getFirst(final FieldKey genericKey) throws KeyNotFoundException
{
return getValue(genericKey, 0);
}
/**
* Retrieve the first value that exists for this asfkey
*
* @param asfKey
* @return
* @throws org.jaudiotagger.tag.KeyNotFoundException
*/
public String getFirst(AsfFieldKey asfKey) throws KeyNotFoundException
{
if (asfKey == null)
{
throw new KeyNotFoundException();
}
return super.getFirst(asfKey.getFieldName());
}
/**
* {@inheritDoc}
*/
public String getValue(final FieldKey genericKey, int index) throws KeyNotFoundException
{
if (genericKey == null)
{
throw new KeyNotFoundException();
}
return super.getItem(tagFieldToAsfField.get(genericKey).getFieldName(), index);
}
/**
* Returns the Copyright.
*
* @return the Copyright.
*/
public String getFirstCopyright()
{
return getFirst(AsfFieldKey.COPYRIGHT.getFieldName());
}
/**
* {@inheritDoc}
*/
@Override
public AsfTagField getFirstField(final FieldKey genericKey) throws KeyNotFoundException
{
if (genericKey == null)
{
throw new KeyNotFoundException();
}
return (AsfTagField) super.getFirstField(tagFieldToAsfField.get(genericKey).getFieldName());
}
/**
* Returns the Rating.
*
* @return the Rating.
*/
public String getFirstRating()
{
return getFirst(AsfFieldKey.RATING.getFieldName());
}
/**
* Returns a list of stored ratings.
*
* @return list of stored ratings.
*/
public List<TagField> getRating()
{
return getFields(AsfFieldKey.RATING.getFieldName());
}
/**
* {@inheritDoc}
*/
@Override
protected boolean isAllowedEncoding(final String enc)
{
return AsfHeader.ASF_CHARSET.name().equals(enc);
}
/**
* If <code>true</code>, the {@link #copyFrom(TagField)} method creates a
* new {@link AsfTagField} instance and copies the content from the source.<br>
* This method is utilized by {@link #addField(TagField)} and
* {@link #setField(TagField)}.<br>
* So if <code>true</code> it is ensured that the {@link AsfTag} instance
* has its own copies of fields, which cannot be modified after assignment
* (which could pass some checks), and it just stores {@link AsfTagField}
* objects.<br>
* Only then {@link #getAsfFields()} can work. otherwise
* {@link IllegalStateException} is thrown.
*
* @return state of field conversion.
*/
public boolean isCopyingFields()
{
return this.copyFields;
}
/**
* Check field is valid and can be added to this tag
*
* @param field field to add
* @return <code>true</code> if field may be added.
*/
// TODO introduce this concept to all formats
private boolean isValidField(final TagField field)
{
if (field == null)
{
return false;
}
if (!(field instanceof AsfTagField))
{
return false;
}
return !field.isEmpty();
}
/**
* {@inheritDoc}
*/
@Override
// TODO introduce copy idea to all formats
public void setField(final TagField field)
{
if (isValidField(field))
{
// Copy only occurs if flag setField
super.setField(copyFrom(field));
}
}
/**
* Sets the copyright.<br>
*
* @param Copyright the copyright to set.
*/
public void setCopyright(final String Copyright)
{
setField(createCopyrightField(Copyright));
}
/**
* Sets the Rating.<br>
*
* @param rating the rating to set.
*/
public void setRating(final String rating)
{
setField(createRatingField(rating));
}
/**
*
* @param genericKey
* @return
*/
public boolean hasField(FieldKey genericKey)
{
AsfFieldKey mp4FieldKey = tagFieldToAsfField.get(genericKey);
return getFields(mp4FieldKey.getFieldName()).size() != 0;
}
/**
*
* @param asfFieldKey
* @return
*/
public boolean hasField(AsfFieldKey asfFieldKey)
{
return getFields(asfFieldKey.getFieldName()).size() != 0;
}
}
|