Coverage Report - org.jaudiotagger.audio.asf.AsfFileReader
 
Classes in this File Line Coverage Branch Coverage Complexity
AsfFileReader
53%
45/84
42%
16/38
7.167
 
 1  
 /*
 2  
  * Entagged Audio Tag library
 3  
  * Copyright (c) 2004-2005 Christian Laireiter <liree@web.de>
 4  
  * 
 5  
  * This library is free software; you can redistribute it and/or
 6  
  * modify it under the terms of the GNU Lesser General Public
 7  
  * License as published by the Free Software Foundation; either
 8  
  * version 2.1 of the License, or (at your option) any later version.
 9  
  *  
 10  
  * This library is distributed in the hope that it will be useful,
 11  
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 12  
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 13  
  * Lesser General Public License for more details.
 14  
  * 
 15  
  * You should have received a copy of the GNU Lesser General Public
 16  
  * License along with this library; if not, write to the Free Software
 17  
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 18  
  */
 19  
 package org.jaudiotagger.audio.asf;
 20  
 
 21  
 import org.jaudiotagger.audio.AudioFile;
 22  
 import org.jaudiotagger.audio.asf.data.AsfHeader;
 23  
 import org.jaudiotagger.audio.asf.data.AudioStreamChunk;
 24  
 import org.jaudiotagger.audio.asf.data.MetadataContainer;
 25  
 import org.jaudiotagger.audio.asf.data.MetadataDescriptor;
 26  
 import org.jaudiotagger.audio.asf.io.*;
 27  
 import org.jaudiotagger.tag.asf.AsfTag;
 28  
 import org.jaudiotagger.audio.asf.util.TagConverter;
 29  
 import org.jaudiotagger.audio.asf.util.Utils;
 30  
 import org.jaudiotagger.audio.exceptions.CannotReadException;
 31  
 import org.jaudiotagger.audio.exceptions.InvalidAudioFrameException;
 32  
 import org.jaudiotagger.audio.exceptions.ReadOnlyFileException;
 33  
 import org.jaudiotagger.audio.generic.AudioFileReader;
 34  
 import org.jaudiotagger.audio.generic.GenericAudioHeader;
 35  
 import org.jaudiotagger.logging.ErrorMessage;
 36  
 import org.jaudiotagger.tag.TagException;
 37  
 
 38  
 import java.io.*;
 39  
 import java.util.ArrayList;
 40  
 import java.util.List;
 41  
 import java.util.logging.Logger;
 42  
 
 43  
 /**
 44  
  * This reader can read ASF files containing any content (stream type). <br>
 45  
  * 
 46  
  * @author Christian Laireiter
 47  
  */
 48  8
 public class AsfFileReader extends AudioFileReader {
 49  
 
 50  
     /**
 51  
      * Logger instance
 52  
      */
 53  4
     private final static Logger LOGGER = Logger
 54  
             .getLogger("org.jaudiotagger.audio.asf");
 55  
 
 56  
     /**
 57  
      * This reader will be configured to read tag and audio header information.<br>
 58  
      */
 59  
     private final static AsfHeaderReader HEADER_READER;
 60  
 
 61  
     static {
 62  4
         final List<Class<? extends ChunkReader>> readers = new ArrayList<Class<? extends ChunkReader>>();
 63  4
         readers.add(ContentDescriptionReader.class);
 64  4
         readers.add(ContentBrandingReader.class);
 65  4
         readers.add(MetadataReader.class);
 66  4
         readers.add(LanguageListReader.class);
 67  
 
 68  
         // Create the header extension object reader with just content
 69  
         // description reader as well
 70  
         // as extended content description reader.
 71  4
         final AsfExtHeaderReader extReader = new AsfExtHeaderReader(readers,
 72  
                 true);
 73  4
         readers.add(FileHeaderReader.class);
 74  4
         readers.add(StreamChunkReader.class);
 75  4
         HEADER_READER = new AsfHeaderReader(readers, true);
 76  4
         HEADER_READER.setExtendedHeaderReader(extReader);
 77  4
     }
 78  
 
 79  
     /**
 80  
      * Determines if the &quot;isVbr&quot; field is set in the extended content
 81  
      * description.<br>
 82  
      * 
 83  
      * @param header
 84  
      *            the header to look up.
 85  
      * @return <code>true</code> if &quot;isVbr&quot; is present with a
 86  
      *         <code>true</code> value.
 87  
      */
 88  
     private boolean determineVariableBitrate(final AsfHeader header) {
 89  198
         assert header != null;
 90  198
         boolean result = false;
 91  198
         final MetadataContainer extDesc = header
 92  
                 .findExtendedContentDescription();
 93  198
         if (extDesc != null) {
 94  154
             final List<MetadataDescriptor> descriptors = extDesc
 95  
                     .getDescriptorsByName("IsVBR");
 96  154
             if (descriptors != null && !descriptors.isEmpty()) {
 97  138
                 result = Boolean.TRUE.toString().equals(
 98  
                         descriptors.get(0).getString());
 99  
             }
 100  
         }
 101  198
         return result;
 102  
     }
 103  
 
 104  
     /**
 105  
      * Creates a generic audio header instance with provided data from header.
 106  
      * 
 107  
      * @param header
 108  
      *            ASF header which contains the information.
 109  
      * @return generic audio header representation.
 110  
      * @throws CannotReadException
 111  
      *             If header does not contain mandatory information. (Audio
 112  
      *             stream chunk and file header chunk)
 113  
      */
 114  
     private GenericAudioHeader getAudioHeader(final AsfHeader header)
 115  
             throws CannotReadException {
 116  198
         final GenericAudioHeader info = new GenericAudioHeader();
 117  198
         if (header.getFileHeader() == null) {
 118  0
             throw new CannotReadException(
 119  
                     "Invalid ASF/WMA file. File header object not available.");
 120  
         }
 121  198
         if (header.getAudioStreamChunk() == null) {
 122  0
             throw new CannotReadException(
 123  
                     "Invalid ASF/WMA file. No audio stream contained.");
 124  
         }
 125  198
         info.setBitrate(header.getAudioStreamChunk().getKbps());
 126  198
         info.setChannelNumber((int) header.getAudioStreamChunk()
 127  
                 .getChannelCount());
 128  198
         info.setEncodingType("ASF (audio): "
 129  
                 + header.getAudioStreamChunk().getCodecDescription());
 130  198
         info
 131  
                 .setLossless(header.getAudioStreamChunk()
 132  
                         .getCompressionFormat() == AudioStreamChunk.WMA_LOSSLESS);
 133  198
         info.setPreciseLength(header.getFileHeader().getPreciseDuration());
 134  198
         info.setSamplingRate((int) header.getAudioStreamChunk()
 135  
                 .getSamplingRate());
 136  198
         info.setVariableBitRate(determineVariableBitrate(header));
 137  198
         return info;
 138  
     }
 139  
 
 140  
     /**
 141  
      * (overridden)
 142  
      * 
 143  
      * @see org.jaudiotagger.audio.generic.AudioFileReader#getEncodingInfo(java.io.RandomAccessFile)
 144  
      */
 145  
     @Override
 146  
     protected GenericAudioHeader getEncodingInfo(final RandomAccessFile raf)
 147  
             throws CannotReadException, IOException {
 148  0
         raf.seek(0);
 149  
         GenericAudioHeader info;
 150  
         try {
 151  0
             final AsfHeader header = AsfHeaderReader.readInfoHeader(raf);
 152  0
             if (header == null) {
 153  0
                 throw new CannotReadException(
 154  
                         "Some values must have been "
 155  
                                 + "incorrect for interpretation as asf with wma content.");
 156  
             }
 157  0
             info = getAudioHeader(header);
 158  0
         } catch (final Exception e) {
 159  0
             if (e instanceof IOException) {
 160  0
                 throw (IOException) e;
 161  0
             } else if (e instanceof CannotReadException) {
 162  0
                 throw (CannotReadException) e;
 163  
             } else {
 164  0
                 throw new CannotReadException("Failed to read. Cause: "
 165  
                         + e.getMessage(), e);
 166  
             }
 167  0
         }
 168  0
         return info;
 169  
     }
 170  
 
 171  
     /**
 172  
      * Creates a tag instance with provided data from header.
 173  
      * 
 174  
      * @param header
 175  
      *            ASF header which contains the information.
 176  
      * @return generic audio header representation.
 177  
      */
 178  
     private AsfTag getTag(final AsfHeader header) {
 179  198
         return TagConverter.createTagOf(header);
 180  
     }
 181  
 
 182  
     /**
 183  
      * (overridden)
 184  
      * 
 185  
      * @see org.jaudiotagger.audio.generic.AudioFileReader#getTag(java.io.RandomAccessFile)
 186  
      */
 187  
     @Override
 188  
     protected AsfTag getTag(final RandomAccessFile raf)
 189  
             throws CannotReadException, IOException {
 190  0
         raf.seek(0);
 191  
         AsfTag tag;
 192  
         try {
 193  0
             final AsfHeader header = AsfHeaderReader.readTagHeader(raf);
 194  0
             if (header == null) {
 195  0
                 throw new CannotReadException(
 196  
                         "Some values must have been "
 197  
                                 + "incorrect for interpretation as asf with wma content.");
 198  
             }
 199  
 
 200  0
             tag = TagConverter.createTagOf(header);
 201  
 
 202  0
         } catch (final Exception e) {
 203  0
             logger.severe(e.getMessage());
 204  0
             if (e instanceof IOException) {
 205  0
                 throw (IOException) e;
 206  0
             } else if (e instanceof CannotReadException) {
 207  0
                 throw (CannotReadException) e;
 208  
             } else {
 209  0
                 throw new CannotReadException("Failed to read. Cause: "
 210  
                         + e.getMessage());
 211  
             }
 212  0
         }
 213  0
         return tag;
 214  
     }
 215  
 
 216  
     /**
 217  
      * {@inheritDoc}
 218  
      */
 219  
     @Override
 220  
     public AudioFile read(final File f) throws CannotReadException,
 221  
             IOException, TagException, ReadOnlyFileException,
 222  
             InvalidAudioFrameException {
 223  198
         if (!f.canRead()) {
 224  0
             throw new CannotReadException(
 225  
                     ErrorMessage.GENERAL_READ_FAILED_DO_NOT_HAVE_PERMISSION_TO_READ_FILE
 226  
                             .getMsg(f.getAbsolutePath()));
 227  
         }
 228  198
         InputStream stream = null;
 229  
         try {
 230  198
             stream = new FullRequestInputStream(new BufferedInputStream(
 231  
                     new FileInputStream(f)));
 232  198
             final AsfHeader header = HEADER_READER.read(Utils.readGUID(stream),
 233  
                     stream, 0);
 234  198
             if (header == null) {
 235  0
                 throw new CannotReadException(ErrorMessage.ASF_HEADER_MISSING
 236  
                         .getMsg(f.getAbsolutePath()));
 237  
             }
 238  198
             if (header.getFileHeader() == null) {
 239  0
                 throw new CannotReadException(
 240  
                         ErrorMessage.ASF_FILE_HEADER_MISSING.getMsg(f
 241  
                                 .getAbsolutePath()));
 242  
             }
 243  
 
 244  
             // Just log a warning because file seems to play okay
 245  198
             if (header.getFileHeader().getFileSize().longValue() != f.length()) {
 246  4
                 logger
 247  
                         .warning(ErrorMessage.ASF_FILE_HEADER_SIZE_DOES_NOT_MATCH_FILE_SIZE
 248  
                                 .getMsg(f.getAbsolutePath(), header
 249  
                                         .getFileHeader().getFileSize()
 250  
                                         .longValue(), f.length()));
 251  
             }
 252  
 
 253  198
             return new AudioFile(f, getAudioHeader(header), getTag(header));
 254  
 
 255  0
         } catch (final CannotReadException e) {
 256  0
             throw e;
 257  0
         } catch (final Exception e) {
 258  0
             throw new CannotReadException("\"" + f + "\" :" + e, e);
 259  
         } finally {
 260  0
             try {
 261  198
                 if (stream != null) {
 262  198
                     stream.close();
 263  
                 }
 264  0
             } catch (final Exception ex) {
 265  0
                 LOGGER.severe("\"" + f + "\" :" + ex);
 266  396
             }
 267  
         }
 268  
     }
 269  
 
 270  
 }