Coverage Report - org.jaudiotagger.tag.datatype.StringFixedLength
 
Classes in this File Line Coverage Branch Coverage Complexity
StringFixedLength
70%
52/74
60%
18/30
5.167
 
 1  
 /**
 2  
  *  @author : Paul Taylor
 3  
  *  @author : Eric Farng
 4  
  *
 5  
  *  Version @version:$Id: StringFixedLength.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.valuepair.TextEncoding;
 29  
 
 30  
 import java.nio.ByteBuffer;
 31  
 import java.nio.CharBuffer;
 32  
 import java.nio.charset.CharacterCodingException;
 33  
 import java.nio.charset.Charset;
 34  
 import java.nio.charset.CharsetDecoder;
 35  
 import java.nio.charset.CharsetEncoder;
 36  
 
 37  
 
 38  
 /**
 39  
  * Represents a fixed length String, whereby the length of the String is known. The String
 40  
  * will be encoded based upon the text encoding of the frame that it belongs to.
 41  
  */
 42  
 public class StringFixedLength extends AbstractString
 43  
 {
 44  
     /**
 45  
      * Creates a new ObjectStringFixedsize datatype.
 46  
      *
 47  
      * @param identifier
 48  
      * @param frameBody
 49  
      * @param size
 50  
      * @throws IllegalArgumentException
 51  
      */
 52  
     public StringFixedLength(String identifier, AbstractTagFrameBody frameBody, int size)
 53  
     {
 54  865
         super(identifier, frameBody);
 55  865
         if (size < 0)
 56  
         {
 57  0
             throw new IllegalArgumentException("size is less than zero: " + size);
 58  
         }
 59  865
         setSize(size);
 60  865
     }
 61  
 
 62  
     public StringFixedLength(StringFixedLength copyObject)
 63  
     {
 64  480
         super(copyObject);
 65  480
         this.size = copyObject.size;
 66  480
     }
 67  
 
 68  
     /**
 69  
      * @param obj
 70  
      * @return if obj is equivalent to this
 71  
      */
 72  
     public boolean equals(Object obj)
 73  
     {
 74  4
         if (!(obj instanceof StringFixedLength))
 75  
         {
 76  0
             return false;
 77  
         }
 78  4
         StringFixedLength object = (StringFixedLength) obj;
 79  4
         return this.size == object.size && super.equals(obj);
 80  
     }
 81  
 
 82  
     /**
 83  
      * Read a string from buffer of fixed size(size has already been set in constructor)
 84  
      *
 85  
      * @param arr    this is the buffer for the frame
 86  
      * @param offset this is where to start reading in the buffer for this field
 87  
      */
 88  
     public void readByteArray(byte[] arr, int offset) throws InvalidDataTypeException
 89  
     {
 90  633
         logger.info("Reading from array from offset:" + offset);
 91  
         try
 92  
         {
 93  633
             String charSetName = getTextEncodingCharSet();
 94  633
             CharsetDecoder decoder = Charset.forName(charSetName).newDecoder();
 95  
 
 96  
             //Decode buffer if runs into problems should through exception which we
 97  
             //catch and then set value to empty string.
 98  633
             logger.finest("Array length is:" + arr.length + "offset is:" + offset + "Size is:" + size);
 99  
 
 100  
 
 101  633
             if (arr.length - offset < size)
 102  
             {
 103  0
                 throw new InvalidDataTypeException("byte array is to small to retrieve string of declared length:" + size);
 104  
             }
 105  633
             String str = decoder.decode(ByteBuffer.wrap(arr, offset, size)).toString();
 106  633
             if (str == null)
 107  
             {
 108  0
                 throw new NullPointerException("String is null");
 109  
             }
 110  633
             value = str;
 111  
         }
 112  0
         catch (CharacterCodingException ce)
 113  
         {
 114  0
             logger.severe(ce.getMessage());
 115  0
             value = "";
 116  633
         }
 117  633
         logger.info("Read StringFixedLength:" + value);
 118  633
     }
 119  
 
 120  
     /**
 121  
      * Write String into byte array
 122  
      * <p/>
 123  
      * The string will be adjusted to ensure the correct number of bytes are written, If the current value is null
 124  
      * or to short the written value will have the 'space' character appended to ensure this. We write this instead of
 125  
      * the null character because the null character is likely to confuse the parser into misreading the next field.
 126  
      *
 127  
      * @return the byte array to be written to the file
 128  
      */
 129  
     public byte[] writeByteArray()
 130  
     {
 131  
         ByteBuffer dataBuffer;
 132  
         byte[] data;
 133  
 
 134  
         //Create with a series of empty of spaces to try and ensure integrity of field
 135  456
         if (value == null)
 136  
         {
 137  16
             logger.warning("Value of StringFixedlength Field is null using default value instead");
 138  16
             data = new byte[size];
 139  64
             for (int i = 0; i < size; i++)
 140  
             {
 141  48
                 data[i] = ' ';
 142  
             }
 143  16
             return data;
 144  
         }
 145  
 
 146  
         try
 147  
         {
 148  440
             String charSetName = getTextEncodingCharSet();
 149  440
             if (charSetName.equals(TextEncoding.CHARSET_UTF_16))
 150  
             {
 151  0
                 charSetName = TextEncoding.CHARSET_UTF_16_ENCODING_FORMAT;
 152  0
                 CharsetEncoder encoder = Charset.forName(charSetName).newEncoder();
 153  
                 //Note remember LE BOM is ff fe but tis is handled by encoder Unicode char is fe ff
 154  0
                 dataBuffer = encoder.encode(CharBuffer.wrap('\ufeff' + (String) value));
 155  0
             }
 156  
             else
 157  
             {
 158  440
                 CharsetEncoder encoder = Charset.forName(charSetName).newEncoder();
 159  440
                 dataBuffer = encoder.encode(CharBuffer.wrap((String) value));
 160  
             }
 161  
         }
 162  0
         catch (CharacterCodingException ce)
 163  
         {
 164  0
             logger.warning("There was a problem writing the following StringFixedlength Field:" + value + ":" + ce.getMessage() + "using default value instead");
 165  0
             data = new byte[size];
 166  0
             for (int i = 0; i < size; i++)
 167  
             {
 168  0
                 data[i] = ' ';
 169  
             }
 170  0
             return data;
 171  440
         }
 172  
 
 173  
         // We must return the defined size.
 174  
         // To check now because size is in bytes not chars
 175  440
         if (dataBuffer != null)
 176  
         {
 177  
             //Everything ok
 178  440
             if (dataBuffer.limit() == size)
 179  
             {
 180  432
                 data = new byte[dataBuffer.limit()];
 181  432
                 dataBuffer.get(data, 0, dataBuffer.limit());
 182  432
                 return data;
 183  
             }
 184  
             //There is more data available than allowed for this field strip
 185  8
             else if (dataBuffer.limit() > size)
 186  
             {
 187  4
                 logger.warning("There was a problem writing the following StringFixedlength Field:" + value + " when converted to bytes has length of:" + dataBuffer.limit() + " but field was defined with length of:" + size + " too long so stripping extra length");
 188  4
                 data = new byte[size];
 189  4
                 dataBuffer.get(data, 0, size);
 190  4
                 return data;
 191  
             }
 192  
             //There is not enough data
 193  
             else
 194  
             {
 195  4
                 logger.warning("There was a problem writing the following StringFixedlength Field:" + value + " when converted to bytes has length of:" + dataBuffer.limit() + " but field was defined with length of:" + size + " too short so padding with spaces to make up extra length");
 196  
 
 197  4
                 data = new byte[size];
 198  4
                 dataBuffer.get(data, 0, dataBuffer.limit());
 199  
 
 200  8
                 for (int i = dataBuffer.limit(); i < size; i++)
 201  
                 {
 202  4
                     data[i] = ' ';
 203  
                 }
 204  4
                 return data;
 205  
             }
 206  
         }
 207  
         else
 208  
         {
 209  0
             logger.warning("There was a serious problem writing the following StringFixedlength Field:" + value + ":" + "using default value instead");
 210  0
             data = new byte[size];
 211  0
             for (int i = 0; i < size; i++)
 212  
             {
 213  0
                 data[i] = ' ';
 214  
             }
 215  0
             return data;
 216  
         }
 217  
     }
 218  
 
 219  
     /**
 220  
      * @return the encoding of the frame body this datatype belongs to
 221  
      */
 222  
     protected String getTextEncodingCharSet()
 223  
     {
 224  61
         byte textEncoding = this.getBody().getTextEncoding();
 225  61
         String charSetName = TextEncoding.getInstanceOf().getValueForId(textEncoding);
 226  61
         logger.finest("text encoding:" + textEncoding + " charset:" + charSetName);
 227  61
         return charSetName;
 228  
     }
 229  
 }