// Path: op1/src/main/java/com/op1/iff/IffReader.java
// public class IffReader implements Closeable {
// 
//     private final DataInputStream dataInputStream;
// 
//     public IffReader(DataInputStream dataInputStream) {
//         this.dataInputStream = dataInputStream;
//     }
// 
//     public SignedChar readSignedChar() throws IOException {
//         return new SignedChar(dataInputStream.readByte());
//     }
// 
//     public UnsignedChar readUnsignedChar() throws IOException {
//         return new UnsignedChar(dataInputStream.readByte());
//     }
// 
//     public SignedShort readSignedShort() throws IOException {
//         return new SignedShort(readBytes(2));
//     }
// 
//     public UnsignedShort readUnsignedShort() throws IOException {
//         return new UnsignedShort(readBytes(2));
//     }
// 
//     public SignedLong readSignedLong() throws IOException {
//         return new SignedLong(readBytes(4));
//     }
// 
//     public UnsignedLong readUnsignedLong() throws IOException {
//         return new UnsignedLong(readBytes(4));
//     }
// 
//     public Extended readExtended() throws IOException {
//         return new Extended(readBytes(10));
//     }
// 
//     public PString readPString() throws IOException {
// 
//         // The first byte contains a count of the text textBytes that follow.
//         final int numTextBytes = dataInputStream.readUnsignedByte();
// 
//         // Read the text bytes.
//         final byte[] textBytes = readBytes(numTextBytes);
// 
//         // The total number of textBytes should be even. A pad byte may have been added to satisfy this rule.
//         int numPadBytes = (numTextBytes + 1) % 2;
// 
//         byte[] pStringBytes = new byte[1 + numTextBytes + numPadBytes];
//         pStringBytes[0] = (byte) numTextBytes;
//         System.arraycopy(textBytes, 0, pStringBytes, 1, textBytes.length);
//         if (numPadBytes == 1) {
//             pStringBytes[pStringBytes.length - 1] = dataInputStream.readByte();
//         }
//         return new PString(pStringBytes);
//     }
// 
//     public ID readID() throws IOException {
//         return new ID(readBytes(4));
//     }
// 
//     public OSType readOSType() throws IOException {
//         return new OSType(readBytes(4));
//     }
// 
//     public byte[] readBytes(int numBytesToRead) throws IOException {
//         final byte[] bytes = new byte[numBytesToRead];
//         final int numRead = dataInputStream.read(bytes);
//         if (numRead != numBytesToRead) {
//             throw new EOFException(String.format("numBytesToRead: %s, numRead: %s", numBytesToRead, numRead));
//         }
//         return bytes;
//     }
// 
//     public byte readByte() throws IOException {
//         return dataInputStream.readByte();
//     }
// 
//     public void close() throws IOException {
//         dataInputStream.close();
//     }
// }
// 
// Path: op1/src/main/java/com/op1/iff/types/ID.java
// public class ID extends DataType {
// 
//     private final String name;
// 
//     public ID(byte[] bytes) {
//         // TODO: ahem, validation?
//         super(bytes, 4);
//         this.name = new String(bytes);
//     }
// 
//     public static ID valueOf(String s) {
//         return new ID(s.getBytes());
//     }
// 
//     public String getName() {
//         return name;
//     }
// 
//     @Override
//     public String toString() {
//         return getName();
//     }
// 
//     @Override
//     public boolean equals(Object o) {
//         if (this == o) return true;
//         if (o == null || getClass() != o.getClass()) return false;
// 
//         final ID id = (ID) o;
// 
//         return Arrays.equals(bytes, id.bytes);
// 
//     }
// 
//     @Override
//     public int hashCode() {
//         return Arrays.hashCode(bytes);
//     }
// }
// 
// Path: op1/src/main/java/com/op1/iff/types/SignedLong.java
// public class SignedLong extends DataType {
// 
// 
//     public SignedLong(byte[] bytes) {
//         super(bytes, 4);
//     }
// 
//     public int toInt() {
//         return ByteBuffer.wrap(bytes).getInt();
//     }
// 
//     public static SignedLong fromInt(int i) {
//         return new SignedLong(ByteBuffer.allocate(4).putInt(i).array());
//     }
// 
//     @Override
//     public String toString() {
//         return String.valueOf(toInt());
//     }
// 
//     @Override
//     public boolean equals(Object o) {
//         if (this == o) return true;
//         if (o == null || getClass() != o.getClass()) return false;
// 
//         final SignedLong that = (SignedLong) o;
// 
//         return Arrays.equals(bytes, that.bytes);
// 
//     }
// 
//     @Override
//     public int hashCode() {
//         return Arrays.hashCode(bytes);
//     }
// }


import com.op1.iff.IffReader;
import com.op1.iff.types.ID;
import com.op1.iff.types.SignedLong;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.*;
package com.op1.aiff;



public class AiffReader implements Closeable {

    private final IffReader iffReader;

    private static final Logger LOGGER = LoggerFactory.getLogger(AiffReader.class);

    public AiffReader(IffReader iffReader) {
        this.iffReader = iffReader;
    }

    public static AiffReader newAiffReader(File file) throws FileNotFoundException {
        final FileInputStream fileInputStream = new FileInputStream(file);
        final BufferedInputStream bufferedInputStream = new BufferedInputStream(fileInputStream);
        final DataInputStream dataInputStream = new DataInputStream(bufferedInputStream);
        final IffReader iffReader = new IffReader(dataInputStream);
        return new AiffReader(iffReader);
    }

    public Aiff readAiff() throws IOException {

        final ID chunkId = iffReader.readID();
// Path: op1/src/main/java/com/op1/iff/IffReader.java
// public class IffReader implements Closeable {
// 
//     private final DataInputStream dataInputStream;
// 
//     public IffReader(DataInputStream dataInputStream) {
//         this.dataInputStream = dataInputStream;
//     }
// 
//     public SignedChar readSignedChar() throws IOException {
//         return new SignedChar(dataInputStream.readByte());
//     }
// 
//     public UnsignedChar readUnsignedChar() throws IOException {
//         return new UnsignedChar(dataInputStream.readByte());
//     }
// 
//     public SignedShort readSignedShort() throws IOException {
//         return new SignedShort(readBytes(2));
//     }
// 
//     public UnsignedShort readUnsignedShort() throws IOException {
//         return new UnsignedShort(readBytes(2));
//     }
// 
//     public SignedLong readSignedLong() throws IOException {
//         return new SignedLong(readBytes(4));
//     }
// 
//     public UnsignedLong readUnsignedLong() throws IOException {
//         return new UnsignedLong(readBytes(4));
//     }
// 
//     public Extended readExtended() throws IOException {
//         return new Extended(readBytes(10));
//     }
// 
//     public PString readPString() throws IOException {
// 
//         // The first byte contains a count of the text textBytes that follow.
//         final int numTextBytes = dataInputStream.readUnsignedByte();
// 
//         // Read the text bytes.
//         final byte[] textBytes = readBytes(numTextBytes);
// 
//         // The total number of textBytes should be even. A pad byte may have been added to satisfy this rule.
//         int numPadBytes = (numTextBytes + 1) % 2;
// 
//         byte[] pStringBytes = new byte[1 + numTextBytes + numPadBytes];
//         pStringBytes[0] = (byte) numTextBytes;
//         System.arraycopy(textBytes, 0, pStringBytes, 1, textBytes.length);
//         if (numPadBytes == 1) {
//             pStringBytes[pStringBytes.length - 1] = dataInputStream.readByte();
//         }
//         return new PString(pStringBytes);
//     }
// 
//     public ID readID() throws IOException {
//         return new ID(readBytes(4));
//     }
// 
//     public OSType readOSType() throws IOException {
//         return new OSType(readBytes(4));
//     }
// 
//     public byte[] readBytes(int numBytesToRead) throws IOException {
//         final byte[] bytes = new byte[numBytesToRead];
//         final int numRead = dataInputStream.read(bytes);
//         if (numRead != numBytesToRead) {
//             throw new EOFException(String.format("numBytesToRead: %s, numRead: %s", numBytesToRead, numRead));
//         }
//         return bytes;
//     }
// 
//     public byte readByte() throws IOException {
//         return dataInputStream.readByte();
//     }
// 
//     public void close() throws IOException {
//         dataInputStream.close();
//     }
// }
// 
// Path: op1/src/main/java/com/op1/iff/types/ID.java
// public class ID extends DataType {
// 
//     private final String name;
// 
//     public ID(byte[] bytes) {
//         // TODO: ahem, validation?
//         super(bytes, 4);
//         this.name = new String(bytes);
//     }
// 
//     public static ID valueOf(String s) {
//         return new ID(s.getBytes());
//     }
// 
//     public String getName() {
//         return name;
//     }
// 
//     @Override
//     public String toString() {
//         return getName();
//     }
// 
//     @Override
//     public boolean equals(Object o) {
//         if (this == o) return true;
//         if (o == null || getClass() != o.getClass()) return false;
// 
//         final ID id = (ID) o;
// 
//         return Arrays.equals(bytes, id.bytes);
// 
//     }
// 
//     @Override
//     public int hashCode() {
//         return Arrays.hashCode(bytes);
//     }
// }
// 
// Path: op1/src/main/java/com/op1/iff/types/SignedLong.java
// public class SignedLong extends DataType {
// 
// 
//     public SignedLong(byte[] bytes) {
//         super(bytes, 4);
//     }
// 
//     public int toInt() {
//         return ByteBuffer.wrap(bytes).getInt();
//     }
// 
//     public static SignedLong fromInt(int i) {
//         return new SignedLong(ByteBuffer.allocate(4).putInt(i).array());
//     }
// 
//     @Override
//     public String toString() {
//         return String.valueOf(toInt());
//     }
// 
//     @Override
//     public boolean equals(Object o) {
//         if (this == o) return true;
//         if (o == null || getClass() != o.getClass()) return false;
// 
//         final SignedLong that = (SignedLong) o;
// 
//         return Arrays.equals(bytes, that.bytes);
// 
//     }
// 
//     @Override
//     public int hashCode() {
//         return Arrays.hashCode(bytes);
//     }
// }


// Path: op1/src/main/java/com/op1/aiff/AiffReader.java
import com.op1.iff.IffReader;
import com.op1.iff.types.ID;
import com.op1.iff.types.SignedLong;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.*;

package com.op1.aiff;



public class AiffReader implements Closeable {

    private final IffReader iffReader;

    private static final Logger LOGGER = LoggerFactory.getLogger(AiffReader.class);

    public AiffReader(IffReader iffReader) {
        this.iffReader = iffReader;
    }

    public static AiffReader newAiffReader(File file) throws FileNotFoundException {
        final FileInputStream fileInputStream = new FileInputStream(file);
        final BufferedInputStream bufferedInputStream = new BufferedInputStream(fileInputStream);
        final DataInputStream dataInputStream = new DataInputStream(bufferedInputStream);
        final IffReader iffReader = new IffReader(dataInputStream);
        return new AiffReader(iffReader);
    }

    public Aiff readAiff() throws IOException {

        final ID chunkId = iffReader.readID();
        final SignedLong chunkSize = iffReader.readSignedLong();