Coverage Report - org.jaudiotagger.tag.id3.framebody.AbstractID3v2FrameBody
 
Classes in this File Line Coverage Branch Coverage Complexity
AbstractID3v2FrameBody
96%
48/50
87%
14/16
2.091
 
 1  
 /**
 2  
  *  @author : Paul Taylor
 3  
  *  @author : Eric Farng
 4  
  *
 5  
  *  Version @version:$Id: AbstractID3v2FrameBody.java 836 2009-11-12 15:44:07Z paultaylor $
 6  
  *
 7  
  *  MusicTag Copyright (C)2003,2004
 8  
  *
 9  
  *  This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser
 10  
  *  General Public  License as published by the Free Software Foundation; either version 2.1 of the License,
 11  
  *  or (at your option) any later version.
 12  
  *
 13  
  *  This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
 14  
  *  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 15  
  *  See the GNU Lesser General Public License for more details.
 16  
  *
 17  
  *  You should have received a copy of the GNU Lesser General Public License along with this library; if not,
 18  
  *  you can get a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software
 19  
  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 20  
  *
 21  
  * Description:
 22  
  * Abstract Superclass of all Frame Bodys
 23  
  *
 24  
  */
 25  
 package org.jaudiotagger.tag.id3.framebody;
 26  
 
 27  
 import org.jaudiotagger.audio.mp3.MP3File;
 28  
 import org.jaudiotagger.tag.InvalidDataTypeException;
 29  
 import org.jaudiotagger.tag.InvalidFrameException;
 30  
 import org.jaudiotagger.tag.InvalidTagException;
 31  
 import org.jaudiotagger.tag.datatype.AbstractDataType;
 32  
 import org.jaudiotagger.tag.id3.AbstractTagFrameBody;
 33  
 
 34  
 import java.io.ByteArrayOutputStream;
 35  
 import java.io.IOException;
 36  
 import java.nio.ByteBuffer;
 37  
 
 38  
 /**
 39  
  * Contains the content for an ID3v2 frame, (the header is held directly within the frame
 40  
  */
 41  
 public abstract class AbstractID3v2FrameBody extends AbstractTagFrameBody
 42  
 {
 43  
     protected static final String TYPE_BODY = "body";
 44  
 
 45  
 
 46  
     /**
 47  
      * Frame Body Size, originally this is size as indicated in frame header
 48  
      * when we come to writing data we recalculate it.
 49  
      */
 50  
     private int size;
 51  
 
 52  
 
 53  
     /**
 54  
      * Create Empty Body. Super Constructor sets up Object list
 55  
      */
 56  
     protected AbstractID3v2FrameBody()
 57  2895
     {
 58  2895
     }
 59  
 
 60  
     /**
 61  
      * Create Body based on another body
 62  
      * @param copyObject
 63  
      */
 64  
     protected AbstractID3v2FrameBody(AbstractID3v2FrameBody copyObject)
 65  
     {
 66  5518
         super(copyObject);
 67  5518
     }
 68  
 
 69  
     /**
 70  
      * Creates a new FrameBody datatype from file. The super
 71  
      * Constructor sets up the Object list for the frame.
 72  
      *
 73  
      * @param byteBuffer from where to read the frame body from
 74  
      * @param frameSize
 75  
      * @throws org.jaudiotagger.tag.InvalidTagException
 76  
      */
 77  
     protected AbstractID3v2FrameBody(ByteBuffer byteBuffer, int frameSize) throws InvalidTagException
 78  
     {
 79  6748
         super();
 80  6748
         setSize(frameSize);
 81  6748
         this.read(byteBuffer);
 82  
 
 83  6731
     }
 84  
 
 85  
     /**
 86  
      * Return the ID3v2 Frame Identifier, must be implemented by concrete subclasses
 87  
      *
 88  
      * @return the frame identifier
 89  
      */
 90  
     public abstract String getIdentifier();
 91  
 
 92  
 
 93  
     /**
 94  
      * Return size of frame body,if framebody already exist will take this value from the frame header
 95  
      * but it is always recalculated before writing any changes back to disk.
 96  
      *
 97  
      * @return size in bytes of this frame body
 98  
      */
 99  
     public int getSize()
 100  
     {
 101  10696
         return size;
 102  
     }
 103  
 
 104  
     /**
 105  
      * Set size based on size passed as parameter from frame header,
 106  
      * done before read
 107  
      * @param size
 108  
      */
 109  
     public void setSize(int size)
 110  
     {
 111  6748
         this.size = size;
 112  6748
     }
 113  
 
 114  
     /**
 115  
      * Set size based on size of the DataTypes making up the body,done after write
 116  
      */
 117  
     public void setSize()
 118  
     {
 119  4357
         size = 0;
 120  4357
         for (AbstractDataType object : objectList)
 121  
         {
 122  10851
             size += object.getSize();
 123  
         }
 124  4357
         }
 125  
 
 126  
     /**
 127  
      * Are two bodies equal
 128  
      *
 129  
      * @param obj
 130  
      */
 131  
     public boolean equals(Object obj)
 132  
     {
 133  4
         return (obj instanceof AbstractID3v2FrameBody) && super.equals(obj);
 134  
         }
 135  
 
 136  
     /**
 137  
      * This reads a frame body from a ByteBuffer into the appropriate FrameBody class and update the position of the
 138  
      * buffer to be just after the end of this framebody
 139  
      * <p/>
 140  
      * The ByteBuffer represents the tag and its position should be at the start of this framebody. The size as
 141  
      * indicated in the header is passed to the frame constructor when reading from file.
 142  
      *
 143  
      * @param byteBuffer file to read
 144  
      * @throws InvalidFrameException if unable to construct a framebody from the ByteBuffer
 145  
      */
 146  
     public void read(ByteBuffer byteBuffer) throws InvalidTagException
 147  
     {
 148  6748
         int size = getSize();
 149  6748
         logger.info("Reading body for" + this.getIdentifier() + ":" + size);
 150  
 
 151  
         //Allocate a buffer to the size of the Frame Body and read from file
 152  6748
         byte[] buffer = new byte[size];
 153  6748
         byteBuffer.get(buffer);
 154  
 
 155  
         //Offset into buffer, incremented by length of previous Datatype
 156  
         //this offset is only used internally to decide where to look for the next
 157  
         //datatype within a framebody, it does not decide where to look for the next frame body
 158  6748
         int offset = 0;
 159  
 
 160  
         //Go through the ObjectList of the Frame reading the data into the
 161  
         //correct datatype.
 162  6748
         for (AbstractDataType object : objectList)
 163  
         {
 164  16683
             logger.finest("offset:" + offset);
 165  
 
 166  
             //The read has extended further than the defined frame size (ok to extend upto
 167  
             //size because the next datatype may be of length 0.)
 168  16683
             if (offset > (size))
 169  
             {
 170  4
                 logger.warning("Invalid Size for FrameBody");
 171  4
                 throw new InvalidFrameException("Invalid size for Frame Body");
 172  
             }
 173  
 
 174  
             //Try and load it with data from the Buffer
 175  
             //if it fails frame is invalid
 176  
             try
 177  
             {
 178  16679
                 object.readByteArray(buffer, offset);
 179  
             }
 180  13
             catch (InvalidDataTypeException e)
 181  
             {
 182  13
                 logger.warning("Invalid DataType for Frame Body:" + e.getMessage());
 183  13
                 throw new InvalidFrameException("Invalid DataType for Frame Body:" + e.getMessage());
 184  16666
             }
 185  
             //Increment Offset to start of next datatype.
 186  16666
             offset += object.getSize();
 187  
         }
 188  6731
     }
 189  
 
 190  
     /**
 191  
      * Write the contents of this datatype to the byte array
 192  
      *
 193  
      * @param tagBuffer
 194  
      * @throws IOException on any I/O error
 195  
      */
 196  
     public void write(ByteArrayOutputStream tagBuffer)
 197  
 
 198  
     {
 199  4357
         logger.info("Writing frame body for" + this.getIdentifier() + ":Est Size:" + size);
 200  
         //Write the various fields to file in order
 201  4357
         for (AbstractDataType object : objectList)
 202  
         {
 203  10851
             byte[] objectData = object.writeByteArray();
 204  10851
             if (objectData != null)
 205  
             {
 206  
                 try
 207  
                 {
 208  10819
                     tagBuffer.write(objectData);
 209  
                 }
 210  0
                 catch (IOException ioe)
 211  
                 {
 212  
                     //This could never happen coz not writing to file, so convert to RuntimeException
 213  0
                     throw new RuntimeException(ioe);
 214  10819
                 }
 215  
             }
 216  10851
         }
 217  4357
         setSize();
 218  4357
         logger.info("Written frame body for" + this.getIdentifier() + ":Real Size:" + size);
 219  
 
 220  4357
     }
 221  
 
 222  
     /**
 223  
      * Return String Representation of Datatype     *
 224  
      */
 225  
     public void createStructure()
 226  
     {
 227  428
         MP3File.getStructureFormatter().openHeadingElement(TYPE_BODY, "");
 228  428
         for (AbstractDataType nextObject : objectList)
 229  
         {
 230  1092
             nextObject.createStructure();
 231  
         }
 232  428
         MP3File.getStructureFormatter().closeHeadingElement(TYPE_BODY);
 233  428
     }
 234  
 }