Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/openjdk-multiarch-jdk8u
Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/classes/com/sun/media/sound/AiffFileReader.java
38924 views
1
/*
2
* Copyright (c) 1999, 2013, 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.DataOutputStream;
30
import java.io.File;
31
import java.io.FileInputStream;
32
import java.io.IOException;
33
import java.io.InputStream;
34
import java.net.URL;
35
36
import javax.sound.sampled.AudioFileFormat;
37
import javax.sound.sampled.AudioFormat;
38
import javax.sound.sampled.AudioInputStream;
39
import javax.sound.sampled.AudioSystem;
40
import javax.sound.sampled.UnsupportedAudioFileException;
41
42
43
/**
44
* AIFF file reader and writer.
45
*
46
* @author Kara Kytle
47
* @author Jan Borgersen
48
* @author Florian Bomers
49
*/
50
public final class AiffFileReader extends SunFileReader {
51
52
private static final int MAX_READ_LENGTH = 8;
53
54
// METHODS TO IMPLEMENT AudioFileReader
55
56
/**
57
* Obtains the audio file format of the input stream provided. The stream must
58
* point to valid audio file data. In general, audio file providers may
59
* need to read some data from the stream before determining whether they
60
* support it. These parsers must
61
* be able to mark the stream, read enough data to determine whether they
62
* support the stream, and, if not, reset the stream's read pointer to its original
63
* position. If the input stream does not support this, this method may fail
64
* with an IOException.
65
* @param stream the input stream from which file format information should be
66
* extracted
67
* @return an <code>AudioFileFormat</code> object describing the audio file format
68
* @throws UnsupportedAudioFileException if the stream does not point to valid audio
69
* file data recognized by the system
70
* @throws IOException if an I/O exception occurs
71
* @see InputStream#markSupported
72
* @see InputStream#mark
73
*/
74
public AudioFileFormat getAudioFileFormat(InputStream stream) throws UnsupportedAudioFileException, IOException {
75
// fix for 4489272: AudioSystem.getAudioFileFormat() fails for InputStream, but works for URL
76
AudioFileFormat aff = getCOMM(stream, true);
77
// the following is not strictly necessary - but was implemented like that in 1.3.0 - 1.4.1
78
// so I leave it as it was. May remove this for 1.5.0
79
stream.reset();
80
return aff;
81
}
82
83
84
/**
85
* Obtains the audio file format of the URL provided. The URL must
86
* point to valid audio file data.
87
* @param url the URL from which file format information should be
88
* extracted
89
* @return an <code>AudioFileFormat</code> object describing the audio file format
90
* @throws UnsupportedAudioFileException if the URL does not point to valid audio
91
* file data recognized by the system
92
* @throws IOException if an I/O exception occurs
93
*/
94
public AudioFileFormat getAudioFileFormat(URL url) throws UnsupportedAudioFileException, IOException {
95
AudioFileFormat fileFormat = null;
96
InputStream urlStream = url.openStream(); // throws IOException
97
try {
98
fileFormat = getCOMM(urlStream, false);
99
} finally {
100
urlStream.close();
101
}
102
return fileFormat;
103
}
104
105
106
/**
107
* Obtains the audio file format of the File provided. The File must
108
* point to valid audio file data.
109
* @param file the File from which file format information should be
110
* extracted
111
* @return an <code>AudioFileFormat</code> object describing the audio file format
112
* @throws UnsupportedAudioFileException if the File does not point to valid audio
113
* file data recognized by the system
114
* @throws IOException if an I/O exception occurs
115
*/
116
public AudioFileFormat getAudioFileFormat(File file) throws UnsupportedAudioFileException, IOException {
117
AudioFileFormat fileFormat = null;
118
FileInputStream fis = new FileInputStream(file); // throws IOException
119
// part of fix for 4325421
120
try {
121
fileFormat = getCOMM(fis, false);
122
} finally {
123
fis.close();
124
}
125
126
return fileFormat;
127
}
128
129
130
131
132
/**
133
* Obtains an audio stream from the input stream provided. The stream must
134
* point to valid audio file data. In general, audio file providers may
135
* need to read some data from the stream before determining whether they
136
* support it. These parsers must
137
* be able to mark the stream, read enough data to determine whether they
138
* support the stream, and, if not, reset the stream's read pointer to its original
139
* position. If the input stream does not support this, this method may fail
140
* with an IOException.
141
* @param stream the input stream from which the <code>AudioInputStream</code> should be
142
* constructed
143
* @return an <code>AudioInputStream</code> object based on the audio file data contained
144
* in the input stream.
145
* @throws UnsupportedAudioFileException if the stream does not point to valid audio
146
* file data recognized by the system
147
* @throws IOException if an I/O exception occurs
148
* @see InputStream#markSupported
149
* @see InputStream#mark
150
*/
151
public AudioInputStream getAudioInputStream(InputStream stream) throws UnsupportedAudioFileException, IOException {
152
// getCOMM leaves the input stream at the beginning of the audio data
153
AudioFileFormat fileFormat = getCOMM(stream, true); // throws UnsupportedAudioFileException, IOException
154
155
// we've got everything, and the stream is at the
156
// beginning of the audio data, so return an AudioInputStream.
157
return new AudioInputStream(stream, fileFormat.getFormat(), fileFormat.getFrameLength());
158
}
159
160
161
/**
162
* Obtains an audio stream from the URL provided. The URL must
163
* point to valid audio file data.
164
* @param url the URL for which the <code>AudioInputStream</code> should be
165
* constructed
166
* @return an <code>AudioInputStream</code> object based on the audio file data pointed
167
* to by the URL
168
* @throws UnsupportedAudioFileException if the URL does not point to valid audio
169
* file data recognized by the system
170
* @throws IOException if an I/O exception occurs
171
*/
172
public AudioInputStream getAudioInputStream(URL url) throws UnsupportedAudioFileException, IOException {
173
InputStream urlStream = url.openStream(); // throws IOException
174
AudioFileFormat fileFormat = null;
175
try {
176
fileFormat = getCOMM(urlStream, false);
177
} finally {
178
if (fileFormat == null) {
179
urlStream.close();
180
}
181
}
182
return new AudioInputStream(urlStream, fileFormat.getFormat(), fileFormat.getFrameLength());
183
}
184
185
186
/**
187
* Obtains an audio stream from the File provided. The File must
188
* point to valid audio file data.
189
* @param file the File for which the <code>AudioInputStream</code> should be
190
* constructed
191
* @return an <code>AudioInputStream</code> object based on the audio file data pointed
192
* to by the File
193
* @throws UnsupportedAudioFileException if the File does not point to valid audio
194
* file data recognized by the system
195
* @throws IOException if an I/O exception occurs
196
*/
197
public AudioInputStream getAudioInputStream(File file)
198
throws UnsupportedAudioFileException, IOException {
199
200
FileInputStream fis = new FileInputStream(file); // throws IOException
201
AudioFileFormat fileFormat = null;
202
// part of fix for 4325421
203
try {
204
fileFormat = getCOMM(fis, false);
205
} finally {
206
if (fileFormat == null) {
207
fis.close();
208
}
209
}
210
return new AudioInputStream(fis, fileFormat.getFormat(), fileFormat.getFrameLength());
211
}
212
213
//--------------------------------------------------------------------
214
215
private AudioFileFormat getCOMM(InputStream is, boolean doReset)
216
throws UnsupportedAudioFileException, IOException {
217
218
DataInputStream dis = new DataInputStream(is);
219
220
if (doReset) {
221
dis.mark(MAX_READ_LENGTH);
222
}
223
224
// assumes a stream at the beginning of the file which has already
225
// passed the magic number test...
226
// leaves the input stream at the beginning of the audio data
227
int fileRead = 0;
228
int dataLength = 0;
229
AudioFormat format = null;
230
231
// Read the magic number
232
int magic = dis.readInt();
233
234
// $$fb: fix for 4369044: javax.sound.sampled.AudioSystem.getAudioInputStream() works wrong with Cp037
235
if (magic != AiffFileFormat.AIFF_MAGIC) {
236
// not AIFF, throw exception
237
if (doReset) {
238
dis.reset();
239
}
240
throw new UnsupportedAudioFileException("not an AIFF file");
241
}
242
243
int length = dis.readInt();
244
int iffType = dis.readInt();
245
fileRead += 12;
246
247
int totallength;
248
if(length <= 0 ) {
249
length = AudioSystem.NOT_SPECIFIED;
250
totallength = AudioSystem.NOT_SPECIFIED;
251
} else {
252
totallength = length + 8;
253
}
254
255
// Is this an AIFC or just plain AIFF file.
256
boolean aifc = false;
257
// $$fb: fix for 4369044: javax.sound.sampled.AudioSystem.getAudioInputStream() works wrong with Cp037
258
if (iffType == AiffFileFormat.AIFC_MAGIC) {
259
aifc = true;
260
}
261
262
// Loop through the AIFF chunks until
263
// we get to the SSND chunk.
264
boolean ssndFound = false;
265
while (!ssndFound) {
266
// Read the chunk name
267
int chunkName = dis.readInt();
268
int chunkLen = dis.readInt();
269
fileRead += 8;
270
271
int chunkRead = 0;
272
273
// Switch on the chunk name.
274
switch (chunkName) {
275
case AiffFileFormat.FVER_MAGIC:
276
// Ignore format version for now.
277
break;
278
279
case AiffFileFormat.COMM_MAGIC:
280
// AIFF vs. AIFC
281
// $$fb: fix for 4399551: Repost of bug candidate: cannot replay aif file (Review ID: 108108)
282
if ((!aifc && chunkLen < 18) || (aifc && chunkLen < 22)) {
283
throw new UnsupportedAudioFileException("Invalid AIFF/COMM chunksize");
284
}
285
// Read header info.
286
int channels = dis.readUnsignedShort();
287
if (channels <= 0) {
288
throw new UnsupportedAudioFileException("Invalid number of channels");
289
}
290
dis.readInt(); // numSampleFrames
291
int sampleSizeInBits = dis.readUnsignedShort();
292
if (sampleSizeInBits < 1 || sampleSizeInBits > 32) {
293
throw new UnsupportedAudioFileException("Invalid AIFF/COMM sampleSize");
294
}
295
float sampleRate = (float) read_ieee_extended(dis);
296
chunkRead += (2 + 4 + 2 + 10);
297
298
// If this is not AIFC then we assume it's
299
// a linearly encoded file.
300
AudioFormat.Encoding encoding = AudioFormat.Encoding.PCM_SIGNED;
301
302
if (aifc) {
303
int enc = dis.readInt(); chunkRead += 4;
304
switch (enc) {
305
case AiffFileFormat.AIFC_PCM:
306
encoding = AudioFormat.Encoding.PCM_SIGNED;
307
break;
308
case AiffFileFormat.AIFC_ULAW:
309
encoding = AudioFormat.Encoding.ULAW;
310
sampleSizeInBits = 8; // Java Sound convention
311
break;
312
default:
313
throw new UnsupportedAudioFileException("Invalid AIFF encoding");
314
}
315
}
316
int frameSize = calculatePCMFrameSize(sampleSizeInBits, channels);
317
//$fb what's that ??
318
//if (sampleSizeInBits == 8) {
319
// encoding = AudioFormat.Encoding.PCM_SIGNED;
320
//}
321
format = new AudioFormat(encoding, sampleRate,
322
sampleSizeInBits, channels,
323
frameSize, sampleRate, true);
324
break;
325
case AiffFileFormat.SSND_MAGIC:
326
// Data chunk.
327
// we are getting *weird* numbers for chunkLen sometimes;
328
// this really should be the size of the data chunk....
329
int dataOffset = dis.readInt();
330
int blocksize = dis.readInt();
331
chunkRead += 8;
332
333
// okay, now we are done reading the header. we need to set the size
334
// of the data segment. we know that sometimes the value we get for
335
// the chunksize is absurd. this is the best i can think of:if the
336
// value seems okay, use it. otherwise, we get our value of
337
// length by assuming that everything left is the data segment;
338
// its length should be our original length (for all AIFF data chunks)
339
// minus what we've read so far.
340
// $$kk: we should be able to get length for the data chunk right after
341
// we find "SSND." however, some aiff files give *weird* numbers. what
342
// is going on??
343
344
if (chunkLen < length) {
345
dataLength = chunkLen - chunkRead;
346
} else {
347
// $$kk: 11.03.98: this seems dangerous!
348
dataLength = length - (fileRead + chunkRead);
349
}
350
ssndFound = true;
351
break;
352
} // switch
353
fileRead += chunkRead;
354
// skip the remainder of this chunk
355
if (!ssndFound) {
356
int toSkip = chunkLen - chunkRead;
357
if (toSkip > 0) {
358
fileRead += dis.skipBytes(toSkip);
359
}
360
}
361
} // while
362
363
if (format == null) {
364
throw new UnsupportedAudioFileException("missing COMM chunk");
365
}
366
AudioFileFormat.Type type = aifc?AudioFileFormat.Type.AIFC:AudioFileFormat.Type.AIFF;
367
368
return new AiffFileFormat(type, totallength, format, dataLength / format.getFrameSize());
369
}
370
371
// HELPER METHODS
372
/** write_ieee_extended(DataOutputStream dos, double f) throws IOException {
373
* Extended precision IEEE floating-point conversion routine.
374
* @argument DataOutputStream
375
* @argument double
376
* @return void
377
* @exception IOException
378
*/
379
private void write_ieee_extended(DataOutputStream dos, double f) throws IOException {
380
381
int exponent = 16398;
382
double highMantissa = f;
383
384
// For now write the integer portion of f
385
// $$jb: 03.30.99: stay in synch with JMF on this!!!!
386
while (highMantissa < 44000) {
387
highMantissa *= 2;
388
exponent--;
389
}
390
dos.writeShort(exponent);
391
dos.writeInt( ((int) highMantissa) << 16);
392
dos.writeInt(0); // low Mantissa
393
}
394
395
396
/**
397
* read_ieee_extended
398
* Extended precision IEEE floating-point conversion routine.
399
* @argument DataInputStream
400
* @return double
401
* @exception IOException
402
*/
403
private double read_ieee_extended(DataInputStream dis) throws IOException {
404
405
double f = 0;
406
int expon = 0;
407
long hiMant = 0, loMant = 0;
408
long t1, t2;
409
double HUGE = ((double)3.40282346638528860e+38);
410
411
412
expon = dis.readUnsignedShort();
413
414
t1 = (long)dis.readUnsignedShort();
415
t2 = (long)dis.readUnsignedShort();
416
hiMant = t1 << 16 | t2;
417
418
t1 = (long)dis.readUnsignedShort();
419
t2 = (long)dis.readUnsignedShort();
420
loMant = t1 << 16 | t2;
421
422
if (expon == 0 && hiMant == 0 && loMant == 0) {
423
f = 0;
424
} else {
425
if (expon == 0x7FFF)
426
f = HUGE;
427
else {
428
expon -= 16383;
429
expon -= 31;
430
f = (hiMant * Math.pow(2, expon));
431
expon -= 32;
432
f += (loMant * Math.pow(2, expon));
433
}
434
}
435
436
return f;
437
}
438
}
439
440