1 /* 2 * Copyright (c) 1999, 2015, 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.DataInputStream; 29 import java.io.EOFException; 30 import java.io.IOException; 31 import java.io.InputStream; 32 33 import javax.sound.sampled.AudioFileFormat; 34 import javax.sound.sampled.AudioFormat; 35 import javax.sound.sampled.AudioSystem; 36 import javax.sound.sampled.UnsupportedAudioFileException; 37 38 /** 39 * WAVE file reader. 40 * 41 * @author Kara Kytle 42 * @author Jan Borgersen 43 * @author Florian Bomers 44 */ 45 public final class WaveFileReader extends SunFileReader { 46 47 @Override 48 AudioFileFormat getAudioFileFormatImpl(final InputStream stream) 49 throws UnsupportedAudioFileException, IOException { 50 51 // assumes sream is rewound 52 53 int nread = 0; 54 int fmt; 55 int length = 0; 56 int wav_type = 0; 57 short channels; 58 long sampleRate; 59 long avgBytesPerSec; 60 short blockAlign; 61 int sampleSizeInBits; 62 AudioFormat.Encoding encoding = null; 63 64 DataInputStream dis = new DataInputStream( stream ); 65 66 int magic = dis.readInt(); 67 int fileLength = rllong(dis); 68 int waveMagic = dis.readInt(); 69 int totallength; 70 if (fileLength <= 0) { 71 fileLength = AudioSystem.NOT_SPECIFIED; 72 totallength = AudioSystem.NOT_SPECIFIED; 73 } else { 74 totallength = fileLength + 8; 75 } 76 77 if ((magic != WaveFileFormat.RIFF_MAGIC) || (waveMagic != WaveFileFormat.WAVE_MAGIC)) { 78 // not WAVE, throw UnsupportedAudioFileException 79 throw new UnsupportedAudioFileException("not a WAVE file"); 80 } 81 82 // find and read the "fmt" chunk 83 // we break out of this loop either by hitting EOF or finding "fmt " 84 while(true) { 85 86 try { 87 fmt = dis.readInt(); 88 nread += 4; 89 if( fmt==WaveFileFormat.FMT_MAGIC ) { 90 // we've found the 'fmt' chunk 91 break; 92 } else { 93 // else not 'fmt', skip this chunk 94 length = rllong(dis); 95 nread += 4; 96 if (length % 2 > 0) length++; 97 nread += dis.skipBytes(length); 98 } 99 } catch (EOFException eof) { 100 // we've reached the end of the file without finding the 'fmt' chunk 101 throw new UnsupportedAudioFileException("Not a valid WAV file"); 102 } 103 } 104 105 // Read the format chunk size. 106 length = rllong(dis); 107 nread += 4; 108 109 // This is the nread position at the end of the format chunk 110 int endLength = nread + length; 111 112 // Read the wave format data out of the format chunk. 113 114 // encoding. 115 wav_type = rlshort(dis); nread += 2; 116 117 if (wav_type == WaveFileFormat.WAVE_FORMAT_PCM) 118 encoding = AudioFormat.Encoding.PCM_SIGNED; // if 8-bit, we need PCM_UNSIGNED, below... 119 else if ( wav_type == WaveFileFormat.WAVE_FORMAT_ALAW ) 120 encoding = AudioFormat.Encoding.ALAW; 121 else if ( wav_type == WaveFileFormat.WAVE_FORMAT_MULAW ) 122 encoding = AudioFormat.Encoding.ULAW; 123 else { 124 // we don't support any other WAVE formats.... 125 throw new UnsupportedAudioFileException("Not a supported WAV file"); 126 } 127 // channels 128 channels = rlshort(dis); nread += 2; 129 if (channels <= 0) { 130 throw new UnsupportedAudioFileException("Invalid number of channels"); 131 } 132 133 // sample rate. 134 sampleRate = rllong(dis); nread += 4; 135 136 // this is the avgBytesPerSec 137 avgBytesPerSec = rllong(dis); nread += 4; 138 139 // this is blockAlign value 140 blockAlign = rlshort(dis); nread += 2; 141 142 // this is the PCM-specific value bitsPerSample 143 sampleSizeInBits = (int)rlshort(dis); nread += 2; 144 if (sampleSizeInBits <= 0) { 145 throw new UnsupportedAudioFileException("Invalid bitsPerSample"); 146 } 147 148 // if sampleSizeInBits==8, we need to use PCM_UNSIGNED 149 if ((sampleSizeInBits==8) && encoding.equals(AudioFormat.Encoding.PCM_SIGNED)) 150 encoding = AudioFormat.Encoding.PCM_UNSIGNED; 151 152 // skip any difference between the length of the format chunk 153 // and what we read 154 155 // if the length of the chunk is odd, there's an extra pad byte 156 // at the end. i've never seen this in the fmt chunk, but we 157 // should check to make sure. 158 159 if (length % 2 != 0) length += 1; 160 161 // $$jb: 07.28.99: endLength>nread, not length>nread. 162 // This fixes #4257986 163 if (endLength > nread) 164 nread += dis.skipBytes(endLength - nread); 165 166 // we have a format now, so find the "data" chunk 167 // we break out of this loop either by hitting EOF or finding "data" 168 // $$kk: if "data" chunk precedes "fmt" chunk we are hosed -- can this legally happen? 169 nread = 0; 170 while(true) { 171 try{ 172 int datahdr = dis.readInt(); 173 nread+=4; 174 if (datahdr == WaveFileFormat.DATA_MAGIC) { 175 // we've found the 'data' chunk 176 break; 177 } else { 178 // else not 'data', skip this chunk 179 int thisLength = rllong(dis); nread += 4; 180 if (thisLength % 2 > 0) thisLength++; 181 nread += dis.skipBytes(thisLength); 182 } 183 } catch (EOFException eof) { 184 // we've reached the end of the file without finding the 'data' chunk 185 throw new UnsupportedAudioFileException("Not a valid WAV file"); 186 } 187 } 188 // this is the length of the data chunk 189 int dataLength = rllong(dis); nread += 4; 190 191 // now build the new AudioFileFormat and return 192 193 AudioFormat format = new AudioFormat(encoding, 194 (float)sampleRate, 195 sampleSizeInBits, channels, 196 calculatePCMFrameSize(sampleSizeInBits, channels), 197 (float)sampleRate, false); 198 199 return new WaveFileFormat(AudioFileFormat.Type.WAVE, 200 totallength, 201 format, 202 dataLength / format.getFrameSize()); 203 } 204 }