829N/A/*
6321N/A * Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved.
829N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
829N/A *
829N/A * This code is free software; you can redistribute it and/or modify it
829N/A * under the terms of the GNU General Public License version 2 only, as
2362N/A * published by the Free Software Foundation. Oracle designates this
829N/A * particular file as subject to the "Classpath" exception as provided
2362N/A * by Oracle in the LICENSE file that accompanied this code.
829N/A *
829N/A * This code is distributed in the hope that it will be useful, but WITHOUT
829N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
829N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
829N/A * version 2 for more details (a copy is included in the LICENSE file that
829N/A * accompanied this code).
829N/A *
829N/A * You should have received a copy of the GNU General Public License version
829N/A * 2 along with this work; if not, write to the Free Software Foundation,
829N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
829N/A *
2362N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
2362N/A * or visit www.oracle.com if you need additional information or have any
2362N/A * questions.
829N/A */
829N/Apackage com.sun.media.sound;
829N/A
829N/Aimport java.io.EOFException;
829N/Aimport java.io.IOException;
829N/Aimport java.io.InputStream;
829N/A
829N/A/**
829N/A * Resource Interchange File Format (RIFF) stream decoder.
829N/A *
829N/A * @author Karl Helgason
829N/A */
6321N/Apublic final class RIFFReader extends InputStream {
829N/A
6321N/A private final RIFFReader root;
829N/A private long filepointer = 0;
6321N/A private final String fourcc;
829N/A private String riff_type = null;
829N/A private long ckSize = 0;
829N/A private InputStream stream;
829N/A private long avail;
829N/A private RIFFReader lastiterator = null;
829N/A
829N/A public RIFFReader(InputStream stream) throws IOException {
829N/A
829N/A if (stream instanceof RIFFReader)
829N/A root = ((RIFFReader)stream).root;
829N/A else
829N/A root = this;
829N/A
829N/A this.stream = stream;
829N/A avail = Integer.MAX_VALUE;
829N/A ckSize = Integer.MAX_VALUE;
829N/A
829N/A // Check for RIFF null paddings,
829N/A int b;
829N/A while (true) {
829N/A b = read();
829N/A if (b == -1) {
829N/A fourcc = ""; // don't put null value into fourcc,
829N/A // because it is expected to
829N/A // always contain a string value
829N/A riff_type = null;
829N/A avail = 0;
829N/A return;
829N/A }
829N/A if (b != 0)
829N/A break;
829N/A }
829N/A
829N/A byte[] fourcc = new byte[4];
829N/A fourcc[0] = (byte) b;
829N/A readFully(fourcc, 1, 3);
829N/A this.fourcc = new String(fourcc, "ascii");
829N/A ckSize = readUnsignedInt();
829N/A
829N/A avail = this.ckSize;
829N/A
829N/A if (getFormat().equals("RIFF") || getFormat().equals("LIST")) {
829N/A byte[] format = new byte[4];
829N/A readFully(format);
829N/A this.riff_type = new String(format, "ascii");
829N/A }
829N/A }
829N/A
829N/A public long getFilePointer() throws IOException {
829N/A return root.filepointer;
829N/A }
829N/A
829N/A public boolean hasNextChunk() throws IOException {
829N/A if (lastiterator != null)
829N/A lastiterator.finish();
829N/A return avail != 0;
829N/A }
829N/A
829N/A public RIFFReader nextChunk() throws IOException {
829N/A if (lastiterator != null)
829N/A lastiterator.finish();
829N/A if (avail == 0)
829N/A return null;
829N/A lastiterator = new RIFFReader(this);
829N/A return lastiterator;
829N/A }
829N/A
829N/A public String getFormat() {
829N/A return fourcc;
829N/A }
829N/A
829N/A public String getType() {
829N/A return riff_type;
829N/A }
829N/A
829N/A public long getSize() {
829N/A return ckSize;
829N/A }
829N/A
829N/A public int read() throws IOException {
829N/A if (avail == 0)
829N/A return -1;
829N/A int b = stream.read();
829N/A if (b == -1)
829N/A return -1;
829N/A avail--;
829N/A filepointer++;
829N/A return b;
829N/A }
829N/A
829N/A public int read(byte[] b, int offset, int len) throws IOException {
829N/A if (avail == 0)
829N/A return -1;
829N/A if (len > avail) {
829N/A int rlen = stream.read(b, offset, (int)avail);
829N/A if (rlen != -1)
829N/A filepointer += rlen;
829N/A avail = 0;
829N/A return rlen;
829N/A } else {
829N/A int ret = stream.read(b, offset, len);
829N/A if (ret == -1)
829N/A return -1;
829N/A avail -= ret;
829N/A filepointer += ret;
829N/A return ret;
829N/A }
829N/A }
829N/A
829N/A public final void readFully(byte b[]) throws IOException {
829N/A readFully(b, 0, b.length);
829N/A }
829N/A
829N/A public final void readFully(byte b[], int off, int len) throws IOException {
829N/A if (len < 0)
829N/A throw new IndexOutOfBoundsException();
829N/A while (len > 0) {
829N/A int s = read(b, off, len);
829N/A if (s < 0)
829N/A throw new EOFException();
829N/A if (s == 0)
829N/A Thread.yield();
829N/A off += s;
829N/A len -= s;
829N/A }
829N/A }
829N/A
829N/A public final long skipBytes(long n) throws IOException {
829N/A if (n < 0)
829N/A return 0;
829N/A long skipped = 0;
829N/A while (skipped != n) {
829N/A long s = skip(n - skipped);
829N/A if (s < 0)
829N/A break;
829N/A if (s == 0)
829N/A Thread.yield();
829N/A skipped += s;
829N/A }
829N/A return skipped;
829N/A }
829N/A
829N/A public long skip(long n) throws IOException {
829N/A if (avail == 0)
829N/A return -1;
829N/A if (n > avail) {
829N/A long len = stream.skip(avail);
829N/A if (len != -1)
829N/A filepointer += len;
829N/A avail = 0;
829N/A return len;
829N/A } else {
829N/A long ret = stream.skip(n);
829N/A if (ret == -1)
829N/A return -1;
829N/A avail -= ret;
829N/A filepointer += ret;
829N/A return ret;
829N/A }
829N/A }
829N/A
829N/A public int available() {
829N/A return (int)avail;
829N/A }
829N/A
829N/A public void finish() throws IOException {
829N/A if (avail != 0) {
829N/A skipBytes(avail);
829N/A }
829N/A }
829N/A
829N/A // Read ASCII chars from stream
829N/A public String readString(int len) throws IOException {
829N/A byte[] buff = new byte[len];
829N/A readFully(buff);
829N/A for (int i = 0; i < buff.length; i++) {
829N/A if (buff[i] == 0) {
829N/A return new String(buff, 0, i, "ascii");
829N/A }
829N/A }
829N/A return new String(buff, "ascii");
829N/A }
829N/A
829N/A // Read 8 bit signed integer from stream
829N/A public byte readByte() throws IOException {
829N/A int ch = read();
829N/A if (ch < 0)
829N/A throw new EOFException();
829N/A return (byte) ch;
829N/A }
829N/A
829N/A // Read 16 bit signed integer from stream
829N/A public short readShort() throws IOException {
829N/A int ch1 = read();
829N/A int ch2 = read();
829N/A if (ch1 < 0)
829N/A throw new EOFException();
829N/A if (ch2 < 0)
829N/A throw new EOFException();
829N/A return (short)(ch1 | (ch2 << 8));
829N/A }
829N/A
829N/A // Read 32 bit signed integer from stream
829N/A public int readInt() throws IOException {
829N/A int ch1 = read();
829N/A int ch2 = read();
829N/A int ch3 = read();
829N/A int ch4 = read();
829N/A if (ch1 < 0)
829N/A throw new EOFException();
829N/A if (ch2 < 0)
829N/A throw new EOFException();
829N/A if (ch3 < 0)
829N/A throw new EOFException();
829N/A if (ch4 < 0)
829N/A throw new EOFException();
829N/A return ch1 + (ch2 << 8) | (ch3 << 16) | (ch4 << 24);
829N/A }
829N/A
829N/A // Read 64 bit signed integer from stream
829N/A public long readLong() throws IOException {
829N/A long ch1 = read();
829N/A long ch2 = read();
829N/A long ch3 = read();
829N/A long ch4 = read();
829N/A long ch5 = read();
829N/A long ch6 = read();
829N/A long ch7 = read();
829N/A long ch8 = read();
829N/A if (ch1 < 0)
829N/A throw new EOFException();
829N/A if (ch2 < 0)
829N/A throw new EOFException();
829N/A if (ch3 < 0)
829N/A throw new EOFException();
829N/A if (ch4 < 0)
829N/A throw new EOFException();
829N/A if (ch5 < 0)
829N/A throw new EOFException();
829N/A if (ch6 < 0)
829N/A throw new EOFException();
829N/A if (ch7 < 0)
829N/A throw new EOFException();
829N/A if (ch8 < 0)
829N/A throw new EOFException();
829N/A return ch1 | (ch2 << 8) | (ch3 << 16) | (ch4 << 24)
829N/A | (ch5 << 32) | (ch6 << 40) | (ch7 << 48) | (ch8 << 56);
829N/A }
829N/A
829N/A // Read 8 bit unsigned integer from stream
829N/A public int readUnsignedByte() throws IOException {
829N/A int ch = read();
829N/A if (ch < 0)
829N/A throw new EOFException();
829N/A return ch;
829N/A }
829N/A
829N/A // Read 16 bit unsigned integer from stream
829N/A public int readUnsignedShort() throws IOException {
829N/A int ch1 = read();
829N/A int ch2 = read();
829N/A if (ch1 < 0)
829N/A throw new EOFException();
829N/A if (ch2 < 0)
829N/A throw new EOFException();
829N/A return ch1 | (ch2 << 8);
829N/A }
829N/A
829N/A // Read 32 bit unsigned integer from stream
829N/A public long readUnsignedInt() throws IOException {
829N/A long ch1 = read();
829N/A long ch2 = read();
829N/A long ch3 = read();
829N/A long ch4 = read();
829N/A if (ch1 < 0)
829N/A throw new EOFException();
829N/A if (ch2 < 0)
829N/A throw new EOFException();
829N/A if (ch3 < 0)
829N/A throw new EOFException();
829N/A if (ch4 < 0)
829N/A throw new EOFException();
829N/A return ch1 + (ch2 << 8) | (ch3 << 16) | (ch4 << 24);
829N/A }
829N/A
829N/A public void close() throws IOException {
829N/A finish();
829N/A if (this == root)
829N/A stream.close();
829N/A stream = null;
829N/A }
829N/A}