Coverage Report - org.jaudiotagger.tag.datatype.NumberVariableLength
 
Classes in this File Line Coverage Branch Coverage Complexity
NumberVariableLength
67%
37/55
60%
18/30
3.2
 
 1  
 /**
 2  
  *  @author : Paul Taylor
 3  
  *  @author : Eric Farng
 4  
  *
 5  
  *  Version @version:$Id: NumberVariableLength.java,v 1.10 2008/07/21 10:45:41 paultaylor Exp $
 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  
  *
 23  
  */
 24  
 package org.jaudiotagger.tag.datatype;
 25  
 
 26  
 import org.jaudiotagger.tag.InvalidDataTypeException;
 27  
 import org.jaudiotagger.tag.id3.AbstractTagFrameBody;
 28  
 import org.jaudiotagger.tag.id3.ID3Tags;
 29  
 
 30  
 /**
 31  
  * Represents a number which may span a number of bytes when written to file depending what size is to be represented.
 32  
  * <p/>
 33  
  * The bitorder in ID3v2 is most significant bit first (MSB). The byteorder in multibyte numbers is most significant
 34  
  * byte first (e.g. $12345678 would be encoded $12 34 56 78), also known as big endian and network byte order.
 35  
  * <p/>
 36  
  * In ID3Specification would be denoted as $xx xx xx xx (xx ...) , this denotes at least four bytes but may be more.
 37  
  * Sometimes may be completely optional (zero bytes)
 38  
  */
 39  
 public class NumberVariableLength extends AbstractDataType
 40  
 {
 41  
     private static final int MINIMUM_NO_OF_DIGITS = 1;
 42  
     private static final int MAXIMUM_NO_OF_DIGITS = 8;
 43  
 
 44  33
     int minLength = MINIMUM_NO_OF_DIGITS;
 45  
 
 46  
 
 47  
     /**
 48  
      * Creates a new ObjectNumberVariableLength datatype, set minimum length to zero
 49  
      * if this datatype is optional.
 50  
      *
 51  
      * @param identifier
 52  
      * @param minimumSize
 53  
      */
 54  
     public NumberVariableLength(String identifier, AbstractTagFrameBody frameBody, int minimumSize)
 55  
     {
 56  32
         super(identifier, frameBody);
 57  
 
 58  
         //Set minimum length, which can be zero if optional
 59  32
         this.minLength = minimumSize;
 60  
 
 61  32
     }
 62  
 
 63  
     public NumberVariableLength(NumberVariableLength copy)
 64  
     {
 65  1
         super(copy);
 66  1
         this.minLength = copy.minLength;
 67  1
     }
 68  
 
 69  
     /**
 70  
      * Return the maximum number of digits that can be used to express the number
 71  
      *
 72  
      * @return the maximum number of digits that can be used to express the number
 73  
      */
 74  
     public int getMaximumLenth()
 75  
     {
 76  0
         return MAXIMUM_NO_OF_DIGITS;
 77  
     }
 78  
 
 79  
     /**
 80  
      * Return the  minimum  number of digits that can be used to express the number
 81  
      *
 82  
      * @return the minimum number of digits that can be used to express the number
 83  
      */
 84  
     public int getMinimumLength()
 85  
     {
 86  0
         return minLength;
 87  
     }
 88  
 
 89  
     /**
 90  
      * @param minimumSize
 91  
      */
 92  
     public void setMinimumSize(int minimumSize)
 93  
     {
 94  0
         if (minimumSize > 0)
 95  
         {
 96  0
             this.minLength = minimumSize;
 97  
         }
 98  0
     }
 99  
 
 100  
     /**
 101  
      * @return the number of bytes required to write this to a file
 102  
      */
 103  
     public int getSize()
 104  
     {
 105  24
         if (value == null)
 106  
         {
 107  0
             return 0;
 108  
         }
 109  
         else
 110  
         {
 111  
             int current;
 112  24
             long temp = ID3Tags.getWholeNumber(value);
 113  24
             int size = 0;
 114  
 
 115  216
             for (int i = MINIMUM_NO_OF_DIGITS; i <= MAXIMUM_NO_OF_DIGITS; i++)
 116  
             {
 117  192
                 current = (byte) temp & 0xFF;
 118  
 
 119  192
                 if (current != 0)
 120  
                 {
 121  12
                     size = i;
 122  
                 }
 123  
 
 124  192
                 temp >>= MAXIMUM_NO_OF_DIGITS;
 125  
             }
 126  
 
 127  24
             return (minLength > size) ? minLength : size;
 128  
         }
 129  
     }
 130  
 
 131  
     /**
 132  
      * @param obj
 133  
      * @return
 134  
      */
 135  
     public boolean equals(Object obj)
 136  
     {
 137  0
         if ((obj instanceof NumberVariableLength) == false)
 138  
         {
 139  0
             return false;
 140  
         }
 141  
 
 142  0
         NumberVariableLength object = (NumberVariableLength) obj;
 143  
 
 144  0
         if (this.minLength != object.minLength)
 145  
         {
 146  0
             return false;
 147  
         }
 148  
 
 149  0
         return super.equals(obj);
 150  
     }
 151  
 
 152  
     /**
 153  
      * Read from Byte Array
 154  
      *
 155  
      * @param arr
 156  
      * @param offset
 157  
      * @throws NullPointerException
 158  
      * @throws IndexOutOfBoundsException
 159  
      */
 160  
     public void readByteArray(byte[] arr, int offset) throws InvalidDataTypeException
 161  
     {
 162  
         //Coding error, should never happen
 163  10
         if (arr == null)
 164  
         {
 165  0
             throw new NullPointerException("Byte array is null");
 166  
         }
 167  
 
 168  
         //Coding error, should never happen as far as I can see
 169  10
         if (offset < 0)
 170  
         {
 171  0
             throw new IllegalArgumentException("negativer offset into an array offset:" + offset);
 172  
         }
 173  
 
 174  
         //If optional then set value to zero, this will mean that if this frame is written back to file it will be created
 175  
         //with this additional datatype wheras it didnt exist but I think this is probably an advantage the frame is
 176  
         //more likely to be parsed by other applications if it contains optional fields.
 177  
         //if not optional problem with this frame
 178  10
         if (offset >= arr.length)
 179  
         {
 180  5
             if (minLength == 0)
 181  
             {
 182  5
                 value = (long) 0;
 183  5
                 return;
 184  
             }
 185  
             else
 186  
             {
 187  0
                 throw new InvalidDataTypeException("Offset to byte array is out of bounds: offset = " + offset + ", array.length = " + arr.length);
 188  
             }
 189  
         }
 190  
 
 191  5
         long lvalue = 0;
 192  
 
 193  
         //Read the bytes (starting from offset), the most significant byte of the number being constructed is read first,
 194  
         //we then shift the resulting long one byte over to make room for the next byte
 195  17
         for (int i = offset; i < arr.length; i++)
 196  
         {
 197  12
             lvalue <<= 8;
 198  12
             lvalue += (arr[i] & 0xff);
 199  
         }
 200  
 
 201  5
         value = lvalue;
 202  5
     }
 203  
 
 204  
 
 205  
     /**
 206  
      * @return String representation of the number
 207  
      */
 208  
     public String toString()
 209  
     {
 210  0
         if (value == null)
 211  
         {
 212  0
             return "";
 213  
         }
 214  
         else
 215  
         {
 216  0
             return value.toString();
 217  
         }
 218  
     }
 219  
 
 220  
     /**
 221  
      * Write to Byte Array
 222  
      *
 223  
      * @return the datatype converted to a byte array
 224  
      */
 225  
     public byte[] writeByteArray()
 226  
     {
 227  7
         int size = getSize();
 228  
         byte[] arr;
 229  
 
 230  7
         if (size == 0)
 231  
         {
 232  4
             arr = new byte[0];
 233  
         }
 234  
         else
 235  
         {
 236  3
             long temp = ID3Tags.getWholeNumber(value);
 237  3
             arr = new byte[size];
 238  
 
 239  
             //keeps shifting the number downwards and masking the last 8 bist to get the value for the next byte
 240  
             //to be written
 241  13
             for (int i = size - 1; i >= 0; i--)
 242  
             {
 243  10
                 arr[i] = (byte) (temp & 0xFF);
 244  10
                 temp >>= 8;
 245  
             }
 246  
         }
 247  7
         return arr;
 248  
     }
 249  
 }