Package org.jaudiotagger.tag.id3.framebody

Source Code of org.jaudiotagger.tag.id3.framebody.AbstractID3v2FrameBody

/**
@author : Paul Taylor
@author : Eric Farng
*
*  Version @version:$Id: AbstractID3v2FrameBody.java 901 2010-05-13 18:28:14Z 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
*
* Description:
* Abstract Superclass of all Frame Bodys
*
*/
package org.jaudiotagger.tag.id3.framebody;

import org.jaudiotagger.audio.mp3.MP3File;
import org.jaudiotagger.tag.InvalidDataTypeException;
import org.jaudiotagger.tag.InvalidFrameException;
import org.jaudiotagger.tag.InvalidTagException;
import org.jaudiotagger.tag.datatype.AbstractDataType;
import org.jaudiotagger.tag.id3.AbstractTagFrameBody;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;

/**
* Contains the content for an ID3v2 frame, (the header is held directly within the frame
*/
public abstract class AbstractID3v2FrameBody extends AbstractTagFrameBody {
    protected static final String TYPE_BODY = "body";


    /**
     * Frame Body Size, originally this is size as indicated in frame header
     * when we come to writing data we recalculate it.
     */
    private int size;


    /**
     * Create Empty Body. Super Constructor sets up Object list
     */
    protected AbstractID3v2FrameBody() {
    }

    /**
     * Create Body based on another body
     *
     * @param copyObject
     */
    protected AbstractID3v2FrameBody(AbstractID3v2FrameBody copyObject) {
        super(copyObject);
    }

    /**
     * Creates a new FrameBody dataType from file. The super
     * Constructor sets up the Object list for the frame.
     *
     * @param byteBuffer from where to read the frame body from
     * @param frameSize
     * @throws org.jaudiotagger.tag.InvalidTagException
     *
     */
    protected AbstractID3v2FrameBody(ByteBuffer byteBuffer, int frameSize) throws InvalidTagException {
        super();
        setSize(frameSize);
        this.read(byteBuffer);

    }

    /**
     * Return the ID3v2 Frame Identifier, must be implemented by concrete subclasses
     *
     * @return the frame identifier
     */
    public abstract String getIdentifier();


    /**
     * Return size of frame body,if frameBody already exist will take this value from the frame header
     * but it is always recalculated before writing any changes back to disk.
     *
     * @return size in bytes of this frame body
     */
    public int getSize() {
        return size;
    }

    /**
     * Set size based on size passed as parameter from frame header,
     * done before read
     *
     * @param size
     */
    public void setSize(int size) {
        this.size = size;
    }

    /**
     * Set size based on size of the DataTypes making up the body,done after write
     */
    public void setSize() {
        size = 0;
        for (AbstractDataType object : objectList) {
            size += object.getSize();
        }
    }

    /**
     * Are two bodies equal
     *
     * @param obj
     */
    public boolean equals(Object obj) {
        return (obj instanceof AbstractID3v2FrameBody) && super.equals(obj);
    }

    /**
     * This reads a frame body from a ByteBuffer into the appropriate FrameBody class and update the position of the
     * buffer to be just after the end of this frameBody
     * <p/>
     * The ByteBuffer represents the tag and its position should be at the start of this frameBody. The size as
     * indicated in the header is passed to the frame constructor when reading from file.
     *
     * @param byteBuffer file to read
     * @throws InvalidFrameException if unable to construct a frameBody from the ByteBuffer
     */
    //TODO why don't we just slice byteBuffer, set limit to size and convert readByteArray to take a ByteBuffer
    //then we wouldn't have to temporary allocate space for the buffer, using lots of needless memory
    //and providing extra work for the garbage collector.
    public void read(ByteBuffer byteBuffer) throws InvalidTagException {
        int size = getSize();
//        logger.info("Reading body for" + this.getIdentifier() + ":" + size);

        //Allocate a buffer to the size of the Frame Body and read from file
        byte[] buffer = new byte[size];
        byteBuffer.get(buffer);

        //Offset into buffer, incremented by length of previous dataType
        //this offset is only used internally to decide where to look for the next
        //dataType within a frameBody, it does not decide where to look for the next frame body
        int offset = 0;

        //Go through the ObjectList of the Frame reading the data into the
        for (AbstractDataType object : objectList)
        //correct dataType.
        {
//            logger.finest("offset:" + offset);

            //The read has extended further than the defined frame size (ok to extend upto
            //size because the next datatype may be of length 0.)
            if (offset > (size)) {
                //logger.warning("Invalid Size for FrameBody");
                throw new InvalidFrameException("Invalid size for Frame Body");
            }

            //Try and load it with data from the Buffer
            //if it fails frame is invalid
            try {
                object.readByteArray(buffer, offset);
            } catch (InvalidDataTypeException e) {
                //logger.warning("Problem reading datatype within Frame Body:" + e.getMessage());
                throw e;
            }
            //Increment Offset to start of next datatype.
            offset += object.getSize();
        }
    }

    /**
     * Write the contents of this datatype to the byte array
     *
     * @param tagBuffer
     * @throws IOException on any I/O error
     */
    public void write(ByteArrayOutputStream tagBuffer)

    {
//        logger.info("Writing frame body for" + this.getIdentifier() + ":Est Size:" + size);
        //Write the various fields to file in order
        for (AbstractDataType object : objectList) {
            byte[] objectData = object.writeByteArray();
            if (objectData != null) {
                try {
                    tagBuffer.write(objectData);
                } catch (IOException ioe) {
                    //This could never happen coz not writing to file, so convert to RuntimeException
                    throw new RuntimeException(ioe);
                }
            }
        }
        setSize();
//        logger.info("Written frame body for" + this.getIdentifier() + ":Real Size:" + size);

    }

    /**
     * Return String Representation of Datatype     *
     */
    public void createStructure() {
        MP3File.getStructureFormatter().openHeadingElement(TYPE_BODY, "");
        for (AbstractDataType nextObject : objectList) {
            nextObject.createStructure();
        }
        MP3File.getStructureFormatter().closeHeadingElement(TYPE_BODY);
    }
}
TOP

Related Classes of org.jaudiotagger.tag.id3.framebody.AbstractID3v2FrameBody

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.