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