1 /* 2 * Copyright (c) 1999, 2016, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package com.sun.media.sound; 27 28 import java.io.BufferedInputStream; 29 import java.io.DataInputStream; 30 import java.io.EOFException; 31 import java.io.File; 32 import java.io.FileInputStream; 33 import java.io.IOException; 34 import java.io.InputStream; 35 import java.net.URL; 36 37 import javax.sound.sampled.AudioFileFormat; 38 import javax.sound.sampled.AudioInputStream; 39 import javax.sound.sampled.UnsupportedAudioFileException; 40 import javax.sound.sampled.spi.AudioFileReader; 41 42 /** 43 * Abstract File Reader class. 44 * 45 * @author Jan Borgersen 46 */ 47 abstract class SunFileReader extends AudioFileReader { 48 49 @Override 50 public final StandardFileFormat getAudioFileFormat(final InputStream stream) 51 throws UnsupportedAudioFileException, IOException { 52 stream.mark(200); // The biggest value which was historically used 53 try { 54 return getAudioFileFormatImpl(stream); 55 } catch (final EOFException ignored) { 56 // the header is less than was expected 57 throw new UnsupportedAudioFileException(); 58 } finally { 59 stream.reset(); 60 } 61 } 62 63 @Override 64 public final AudioFileFormat getAudioFileFormat(final URL url) 65 throws UnsupportedAudioFileException, IOException { 66 try (InputStream is = url.openStream()) { 67 return getAudioFileFormatImpl(new BufferedInputStream(is)); 68 } catch (final EOFException ignored) { 69 // the header is less than was expected 70 throw new UnsupportedAudioFileException(); 71 } 72 } 73 74 @Override 75 public final AudioFileFormat getAudioFileFormat(final File file) 76 throws UnsupportedAudioFileException, IOException { 77 try (InputStream is = new FileInputStream(file)) { 78 return getAudioFileFormatImpl(new BufferedInputStream(is)); 79 } catch (final EOFException ignored) { 80 // the header is less than was expected 81 throw new UnsupportedAudioFileException(); 82 } 83 } 84 85 @Override 86 public AudioInputStream getAudioInputStream(final InputStream stream) 87 throws UnsupportedAudioFileException, IOException { 88 stream.mark(200); // The biggest value which was historically used 89 try { 90 final StandardFileFormat format = getAudioFileFormatImpl(stream); 91 // we've got everything, the stream is supported and it is at the 92 // beginning of the audio data, so return an AudioInputStream 93 return new AudioInputStream(stream, format.getFormat(), 94 format.getLongFrameLength()); 95 } catch (UnsupportedAudioFileException | EOFException ignored) { 96 // stream is unsupported or the header is less than was expected 97 stream.reset(); 98 throw new UnsupportedAudioFileException(); 99 } 100 } 101 102 @Override 103 public final AudioInputStream getAudioInputStream(final URL url) 104 throws UnsupportedAudioFileException, IOException { 105 final InputStream urlStream = url.openStream(); 106 try { 107 return getAudioInputStream(new BufferedInputStream(urlStream)); 108 } catch (final Throwable e) { 109 closeSilently(urlStream); 110 throw e; 111 } 112 } 113 114 @Override 115 public final AudioInputStream getAudioInputStream(final File file) 116 throws UnsupportedAudioFileException, IOException { 117 final InputStream fileStream = new FileInputStream(file); 118 try { 119 return getAudioInputStream(new BufferedInputStream(fileStream)); 120 } catch (final Throwable e) { 121 closeSilently(fileStream); 122 throw e; 123 } 124 } 125 126 /** 127 * Obtains the audio file format of the input stream provided. The stream 128 * must point to valid audio file data. Note that default implementation of 129 * {@link #getAudioInputStream(InputStream)} assume that this method leaves 130 * the input stream at the beginning of the audio data. 131 * 132 * @param stream the input stream from which file format information should 133 * be extracted 134 * @return an {@code AudioFileFormat} object describing the audio file 135 * format 136 * @throws UnsupportedAudioFileException if the stream does not point to 137 * valid audio file data recognized by the system 138 * @throws IOException if an I/O exception occurs 139 * @throws EOFException is used incorrectly by our readers instead of 140 * UnsupportedAudioFileException if the header is less than was 141 * expected 142 */ 143 abstract StandardFileFormat getAudioFileFormatImpl(InputStream stream) 144 throws UnsupportedAudioFileException, IOException; 145 146 // HELPER METHODS 147 148 /** 149 * Closes the InputStream when we have read all necessary data from it, and 150 * ignores an IOException. 151 * 152 * @param is the InputStream which should be closed 153 */ 154 private static void closeSilently(final InputStream is) { 155 try { 156 is.close(); 157 } catch (final IOException ignored) { 158 // IOException is ignored 159 } 160 } 161 162 /** 163 * rllong 164 * Protected helper method to read 64 bits and changing the order of 165 * each bytes. 166 * @param DataInputStream 167 * @return 32 bits swapped value. 168 * @exception IOException 169 */ 170 final int rllong(DataInputStream dis) throws IOException { 171 172 int b1, b2, b3, b4 ; 173 int i = 0; 174 175 i = dis.readInt(); 176 177 b1 = ( i & 0xFF ) << 24 ; 178 b2 = ( i & 0xFF00 ) << 8; 179 b3 = ( i & 0xFF0000 ) >> 8; 180 b4 = ( i & 0xFF000000 ) >>> 24; 181 182 i = ( b1 | b2 | b3 | b4 ); 183 184 return i; 185 } 186 187 /** 188 * big2little 189 * Protected helper method to swap the order of bytes in a 32 bit int 190 * @param int 191 * @return 32 bits swapped value 192 */ 193 final int big2little(int i) { 194 195 int b1, b2, b3, b4 ; 196 197 b1 = ( i & 0xFF ) << 24 ; 198 b2 = ( i & 0xFF00 ) << 8; 199 b3 = ( i & 0xFF0000 ) >> 8; 200 b4 = ( i & 0xFF000000 ) >>> 24; 201 202 i = ( b1 | b2 | b3 | b4 ); 203 204 return i; 205 } 206 207 /** 208 * rlshort 209 * Protected helper method to read 16 bits value. Swap high with low byte. 210 * @param DataInputStream 211 * @return the swapped value. 212 * @exception IOException 213 */ 214 final short rlshort(DataInputStream dis) throws IOException { 215 216 short s=0; 217 short high, low; 218 219 s = dis.readShort(); 220 221 high = (short)(( s & 0xFF ) << 8) ; 222 low = (short)(( s & 0xFF00 ) >>> 8); 223 224 s = (short)( high | low ); 225 226 return s; 227 } 228 229 /** 230 * big2little 231 * Protected helper method to swap the order of bytes in a 16 bit short 232 * @param int 233 * @return 16 bits swapped value 234 */ 235 final short big2littleShort(short i) { 236 237 short high, low; 238 239 high = (short)(( i & 0xFF ) << 8) ; 240 low = (short)(( i & 0xFF00 ) >>> 8); 241 242 i = (short)( high | low ); 243 244 return i; 245 } 246 247 /** Calculates the frame size for PCM frames. 248 * Note that this method is appropriate for non-packed samples. 249 * For instance, 12 bit, 2 channels will return 4 bytes, not 3. 250 * @param sampleSizeInBits the size of a single sample in bits 251 * @param channels the number of channels 252 * @return the size of a PCM frame in bytes. 253 */ 254 static final int calculatePCMFrameSize(int sampleSizeInBits, int channels) { 255 return ((sampleSizeInBits + 7) / 8) * channels; 256 } 257 }