📄 id3v23frame.java
字号:
/*
* 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
*/
package com.hadeslee.audiotag.tag.id3;
import com.hadeslee.audiotag.FileConstants;
import com.hadeslee.audiotag.audio.mp3.MP3File;
import com.hadeslee.audiotag.audio.generic.Utils;
import com.hadeslee.audiotag.tag.EmptyFrameException;
import com.hadeslee.audiotag.tag.InvalidFrameException;
import com.hadeslee.audiotag.tag.InvalidFrameIdentifierException;
import com.hadeslee.audiotag.tag.id3.framebody.AbstractID3v2FrameBody;
import com.hadeslee.audiotag.tag.id3.framebody.FrameBodyDeprecated;
import com.hadeslee.audiotag.tag.id3.framebody.FrameBodyUnsupported;
import com.hadeslee.audiotag.tag.id3.framebody.ID3v23FrameBody;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.zip.DataFormatException;
import java.util.zip.Inflater;
/**
* Represents an ID3v2.3 frame.
*
* @author : Paul Taylor
* @author : Eric Farng
* @version $Id: ID3v23Frame.java,v 1.34 2007/11/29 12:05:26 paultaylor Exp $
*/
public class ID3v23Frame extends AbstractID3v2Frame
{
Pattern validFrameIdentifier = Pattern.compile("[A-Z][0-9A-Z]{3}");
protected static final int FRAME_ID_SIZE = 4;
protected static final int FRAME_FLAGS_SIZE = 2;
protected static final int FRAME_SIZE_SIZE = 4;
protected static final int FRAME_COMPRESSION_UNCOMPRESSED_SIZE =4;
protected static final int FRAME_ENCRYPTION_INDICATOR_SIZE =1;
protected static final int FRAME_GROUPING_INDICATOR_SIZE =1;
protected static final int FRAME_HEADER_SIZE = FRAME_ID_SIZE + FRAME_SIZE_SIZE + FRAME_FLAGS_SIZE;
/**
* Creates a new ID3v23 Frame
*/
public ID3v23Frame()
{
}
/**
* Creates a new ID3v23 Frame of type identifier.
*
* <p>An empty body of the correct type will be automatically created.
* This constructor should be used when wish to create a new
* frame from scratch using user data.
*/
public ID3v23Frame(String identifier)
{
super(identifier);
statusFlags = new StatusFlags();
encodingFlags = new EncodingFlags();
}
/**
* Copy Constructor
*
* Creates a new v23 frame based on another v23 frame
*/
public ID3v23Frame(ID3v23Frame frame)
{
super(frame);
statusFlags = new StatusFlags(frame.getStatusFlags().getOriginalFlags());
encodingFlags = new EncodingFlags(frame.getEncodingFlags().getFlags());
}
/**
* Creates a new ID3v23Frame based on another frame.
*
* @param frame
*/
public ID3v23Frame(AbstractID3v2Frame frame) throws InvalidFrameException
{
logger.info("Creating frame from a frame of a different version");
if ((frame instanceof ID3v23Frame == true) && (frame instanceof ID3v24Frame == false))
{
throw new UnsupportedOperationException("Copy Constructor not called. Please type cast the argument");
}
if (frame instanceof ID3v24Frame)
{
statusFlags = new StatusFlags((ID3v24Frame.StatusFlags) frame.getStatusFlags());
encodingFlags = new EncodingFlags(frame.getEncodingFlags().getFlags());
}
if (frame instanceof ID3v24Frame)
{
if(ID3Tags.isID3v24FrameIdentifier(frame.getIdentifier()))
{
//Version between v4 and v3
identifier = ID3Tags.convertFrameID24To23(frame.getIdentifier());
if (identifier != null)
{
logger.info("V4:Orig id is:" + frame.getIdentifier() + ":New id is:" + identifier);
this.frameBody = (AbstractID3v2FrameBody) ID3Tags.copyObject(frame.getBody());
this.frameBody.setHeader(this);
return;
}
else
{
//Is it a known v4 frame which needs forcing to v3 frame e.g. TDRC - TYER,TDAT
identifier = ID3Tags.forceFrameID24To23(frame.getIdentifier());
if(identifier!=null)
{
logger.info("V4:Orig id is:" + frame.getIdentifier() + ":New id is:" + identifier);
this.frameBody = this.readBody(identifier, (AbstractID3v2FrameBody) frame.getBody());
this.frameBody.setHeader(this);
return;
}
//It is a v24 frame that is not known and cannot be forced in v23 e.g TDRL,in which case
//we convert to a framebody unsupported by writing contents as a byte array and feeding
//it into FrameBodyUnsupported
else
{
ByteArrayOutputStream baos = new ByteArrayOutputStream();
((AbstractID3v2FrameBody)frame.getBody()).write(baos);
identifier = frame.getIdentifier();
this.frameBody = new FrameBodyUnsupported(identifier,baos.toByteArray());
this.frameBody.setHeader(this);
logger.info("V4:Orig id is:" + frame.getIdentifier() + ":New Id Unsupported is:" + identifier);
return;
}
}
}
//Unknown Frame e.g NCON
else if(frame.getBody() instanceof FrameBodyUnsupported)
{
this.frameBody = new FrameBodyUnsupported((FrameBodyUnsupported) frame.getBody());
this.frameBody.setHeader(this);
identifier = frame.getIdentifier();
logger.info("UNKNOWN:Orig id is:" + frame.getIdentifier() + ":New id is:" + identifier);
return;
}
// Deprecated frame for v24
else if(frame.getBody() instanceof FrameBodyDeprecated)
{
//Was it valid for this tag version, if so try and reconstruct
if(ID3Tags.isID3v23FrameIdentifier(frame.getIdentifier()))
{
this.frameBody = ((FrameBodyDeprecated)frame.getBody()).getOriginalFrameBody();
this.frameBody.setHeader(this);
identifier = frame.getIdentifier();
logger.info("DEPRECATED:Orig id is:" + frame.getIdentifier() + ":New id is:" + identifier);
}
//or was it still deprecated, if so leave as is
else
{
this.frameBody = new FrameBodyDeprecated((FrameBodyDeprecated) frame.getBody());
this.frameBody.setHeader(this);
identifier = frame.getIdentifier();
logger.info("DEPRECATED:Orig id is:" + frame.getIdentifier() + ":New id is:" + identifier);
return;
}
}
// Unable to find a suitable framebody, this shold not happen
else
{
logger.severe("Orig id is:" + frame.getIdentifier() + "Unable to create Frame Body");
throw new InvalidFrameException("Orig id is:" + frame.getIdentifier() + "Unable to create Frame Body");
}
}
else if (frame instanceof ID3v22Frame)
{
if(ID3Tags.isID3v22FrameIdentifier(frame.getIdentifier()))
{
identifier = ID3Tags.convertFrameID22To23(frame.getIdentifier());
if (identifier != null)
{
logger.info("V3:Orig id is:" + frame.getIdentifier() + ":New id is:" + identifier);
this.frameBody = (AbstractID3v2FrameBody) ID3Tags.copyObject(frame.getBody());
this.frameBody.setHeader(this);
return;
}
//Is it a known v2 frame which needs forcing to v4 frame e.g PIC - APIC
else if (ID3Tags.isID3v22FrameIdentifier(frame.getIdentifier()) == true)
{
//Force v2 to v3
identifier = ID3Tags.forceFrameID22To23(frame.getIdentifier());
if(identifier!=null)
{
logger.info("V22Orig id is:" + frame.getIdentifier() + "New id is:" + identifier);
this.frameBody = this.readBody(identifier, (AbstractID3v2FrameBody) frame.getBody());
this.frameBody.setHeader(this);
return;
}
//No mechanism exists to convert it to a v23 frame
else
{
this.frameBody = new FrameBodyDeprecated((AbstractID3v2FrameBody)frame.getBody());
this.frameBody.setHeader(this);
identifier = frame.getIdentifier();
logger.info("Deprecated:V22:orig id id is:" + frame.getIdentifier() + ":New id is:" + identifier);
return;
}
}
}
// Unknown Frame e.g NCON
else
{
this.frameBody = new FrameBodyUnsupported((FrameBodyUnsupported) frame.getBody());
this.frameBody.setHeader(this);
identifier = frame.getIdentifier();
logger.info("UNKNOWN:Orig id is:" + frame.getIdentifier() + ":New id is:" + identifier);
return;
}
}
logger.warning("Frame is unknown version");
}
/**
* Creates a new ID3v23Frame datatype by reading from byteBuffer.
*
* @param byteBuffer to read from
*/
public ID3v23Frame(ByteBuffer byteBuffer,String loggingFilename)
throws InvalidFrameException
{
setLoggingFilename(loggingFilename);
read(byteBuffer);
}
/**
* Creates a new ID3v23Frame datatype by reading from byteBuffer.
*
* @param byteBuffer to read from
*
* @deprecated use {@link #ID3v23Frame(ByteBuffer,String)} instead
*/
public ID3v23Frame(ByteBuffer byteBuffer)
throws InvalidFrameException
{
this(byteBuffer,"");
}
/**
* Return size of frame
*
* @return int frame size
*/
public int getSize()
{
return frameBody.getSize() + ID3v23Frame.FRAME_HEADER_SIZE;
}
/**
* Compare for equality
* To be deemed equal obj must be a IDv23Frame with the same identifier
* and the same flags.
* containing the same body,datatype list ectera.
* equals() method is made up from all the various components
*
* @param obj
* @return if true if this object is equivalent to obj
*/
public boolean equals(Object obj)
{
if ((obj instanceof ID3v23Frame) == false)
{
return false;
}
ID3v23Frame object = (ID3v23Frame) obj;
if (this.statusFlags.getOriginalFlags() != object.statusFlags.getOriginalFlags())
{
return false;
}
if (this.encodingFlags.getFlags() != object.encodingFlags.getFlags())
{
return false;
}
return super.equals(obj);
}
/**
* Read the frame from a bytebuffer
*
* @param byteBuffer buffer to read from
*/
public void read(ByteBuffer byteBuffer)
throws InvalidFrameException
{
logger.info(getLoggingFilename()+":Read Frame from byteBuffer");
if(byteBuffer.position()+ FRAME_HEADER_SIZE >= byteBuffer.limit())
{
logger.warning(getLoggingFilename()+":No space to find another frame:");
throw new InvalidFrameException(getLoggingFilename()+":No space to find another frame");
}
byte[] buffer = new byte[FRAME_ID_SIZE];
// Read the Frame Identifier
byteBuffer.get(buffer, 0, FRAME_ID_SIZE);
identifier = new String(buffer);
// Is this a valid identifier?
if (isValidID3v2FrameIdentifier(identifier) == false)
{
logger.info(getLoggingFilename()+":Invalid identifier:" + identifier);
byteBuffer.position(byteBuffer.position() - (FRAME_ID_SIZE - 1));
throw new InvalidFrameIdentifierException(getLoggingFilename()+":"+identifier + "is not a valid ID3v2.30 frame");
}
//Read the size field (as Big Endian Int - byte buffers always initlised to Big endian order)
frameSize = byteBuffer.getInt();
if (frameSize < 0)
{
logger.warning(getLoggingFilename()+":Invalid Frame Size:" + identifier);
throw new InvalidFrameException(identifier + " is invalid frame");
}
else if (frameSize == 0)
{
logger.warning(getLoggingFilename()+":Empty Frame Size:" + identifier);
throw new EmptyFrameException(identifier + " is empty frame");
}
else if (frameSize > byteBuffer.remaining())
{
logger.warning(getLoggingFilename()+":Invalid Frame size larger than size before mp3 audio:" + identifier);
throw new InvalidFrameException(identifier + " is invalid frame");
}
//Read the flag bytes
statusFlags = new StatusFlags(byteBuffer.get());
encodingFlags = new EncodingFlags(byteBuffer.get());
String id;
//If this identifier is a valid v24 identifier or easily converted to v24
id = (String) ID3Tags.convertFrameID23To24(identifier);
// Cant easily be converted to v23 but is it a valid v24 identifier
if (id == null)
{
// It is a valid v23 identifier so should be able to find a
// frame body for it.
if (ID3Tags.isID3v23FrameIdentifier(identifier) == true)
{
id = identifier;
}
// Unknown so will be created as FrameBodyUnsupported
else
{
id = UNSUPPORTED_ID;
}
}
logger.fine(getLoggingFilename()+":Identifier was:" + identifier + " reading using:" + id + "with frame size:"+frameSize);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -