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