1/* 2 * Copyright (c) 1999, 2017, 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 26package com.sun.media.sound; 27 28import java.io.BufferedInputStream; 29import java.io.DataInputStream; 30import java.io.EOFException; 31import java.io.File; 32import java.io.FileInputStream; 33import java.io.IOException; 34import java.io.InputStream; 35import java.net.URL; 36 37import javax.sound.sampled.AudioFileFormat; 38import javax.sound.sampled.AudioInputStream; 39import javax.sound.sampled.UnsupportedAudioFileException; 40import javax.sound.sampled.spi.AudioFileReader; 41 42/** 43 * Abstract File Reader class. 44 * 45 * @author Jan Borgersen 46 */ 47abstract 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 * @return 32 bits swapped value. 167 * @exception IOException 168 */ 169 final int rllong(DataInputStream dis) throws IOException { 170 171 int b1, b2, b3, b4 ; 172 int i = 0; 173 174 i = dis.readInt(); 175 176 b1 = ( i & 0xFF ) << 24 ; 177 b2 = ( i & 0xFF00 ) << 8; 178 b3 = ( i & 0xFF0000 ) >> 8; 179 b4 = ( i & 0xFF000000 ) >>> 24; 180 181 i = ( b1 | b2 | b3 | b4 ); 182 183 return i; 184 } 185 186 /** 187 * big2little 188 * Protected helper method to swap the order of bytes in a 32 bit int 189 * @return 32 bits swapped value 190 */ 191 final int big2little(int i) { 192 193 int b1, b2, b3, b4 ; 194 195 b1 = ( i & 0xFF ) << 24 ; 196 b2 = ( i & 0xFF00 ) << 8; 197 b3 = ( i & 0xFF0000 ) >> 8; 198 b4 = ( i & 0xFF000000 ) >>> 24; 199 200 i = ( b1 | b2 | b3 | b4 ); 201 202 return i; 203 } 204 205 /** 206 * rlshort 207 * Protected helper method to read 16 bits value. Swap high with low byte. 208 * @return the swapped value. 209 * @exception IOException 210 */ 211 final short rlshort(DataInputStream dis) throws IOException { 212 213 short s=0; 214 short high, low; 215 216 s = dis.readShort(); 217 218 high = (short)(( s & 0xFF ) << 8) ; 219 low = (short)(( s & 0xFF00 ) >>> 8); 220 221 s = (short)( high | low ); 222 223 return s; 224 } 225 226 /** 227 * big2little 228 * Protected helper method to swap the order of bytes in a 16 bit short 229 * @return 16 bits swapped value 230 */ 231 final short big2littleShort(short i) { 232 233 short high, low; 234 235 high = (short)(( i & 0xFF ) << 8) ; 236 low = (short)(( i & 0xFF00 ) >>> 8); 237 238 i = (short)( high | low ); 239 240 return i; 241 } 242 243 /** Calculates the frame size for PCM frames. 244 * Note that this method is appropriate for non-packed samples. 245 * For instance, 12 bit, 2 channels will return 4 bytes, not 3. 246 * @param sampleSizeInBits the size of a single sample in bits 247 * @param channels the number of channels 248 * @return the size of a PCM frame in bytes. 249 */ 250 static final int calculatePCMFrameSize(int sampleSizeInBits, int channels) { 251 try { 252 return Math.multiplyExact((sampleSizeInBits + 7) / 8, channels); 253 } catch (final ArithmeticException ignored) { 254 return 0; 255 } 256 } 257} 258