001package net.bramp.ffmpeg.nut;
002
003import static com.google.common.base.Preconditions.checkNotNull;
004
005import com.google.common.io.CountingInputStream;
006import java.io.DataInput;
007import java.io.DataInputStream;
008import java.io.IOException;
009import java.io.InputStream;
010import net.bramp.ffmpeg.io.CRC32InputStream;
011
012/** A DataInputStream that implements a couple of custom FFmpeg Nut datatypes. */
013public class NutDataInputStream implements DataInput {
014
015  final DataInputStream in;
016  final CRC32InputStream crc;
017  final CountingInputStream count;
018
019  // These are for debugging, remove later
020  long startCrcRange;
021  long endCrcRange;
022
023  /** Constructs a new NutDataInputStream wrapping the given input stream. */
024  public NutDataInputStream(InputStream in) {
025    checkNotNull(in);
026    this.count = new CountingInputStream(in);
027    this.crc = new CRC32InputStream(count);
028    this.in = new DataInputStream(crc);
029  }
030
031  /** Resets the CRC32 checksum for a new calculation range. */
032  public void resetCRC() {
033    startCrcRange = count.getCount();
034    crc.resetCrc();
035  }
036
037  /** Returns the current CRC32 checksum value. */
038  public long getCRC() {
039    endCrcRange = count.getCount();
040    return crc.getValue();
041  }
042
043  /** Reads a variable-length encoded integer up to 32 bits. */
044  public int readVarInt() throws IOException {
045    boolean more;
046    int result = 0;
047    do {
048      int b = in.readUnsignedByte();
049      more = (b & 0x80) == 0x80;
050      result = 128 * result + (b & 0x7F);
051
052      // TODO Check for int overflow
053    } while (more);
054
055    return result;
056  }
057
058  /** Reads a variable-length encoded integer up to 64 bits. */
059  public long readVarLong() throws IOException {
060    boolean more;
061    long result = 0;
062    do {
063      int b = in.readUnsignedByte();
064      more = (b & 0x80) == 0x80;
065      result = 128 * result + (b & 0x7F);
066
067      // TODO Check for long overflow
068    } while (more);
069
070    return result;
071  }
072
073  /** Reads a signed variable-length encoded integer. */
074  public long readSignedVarInt() throws IOException {
075    long temp = readVarLong() + 1;
076    if ((temp & 1) == 1) {
077      return -(temp >> 1);
078    }
079    return temp >> 1;
080  }
081
082  /** Reads a byte array prefixed with a variable-length encoded length. */
083  public byte[] readVarArray() throws IOException {
084    int len = (int) readVarLong();
085    byte[] result = new byte[len];
086    in.read(result);
087    return result;
088  }
089
090  /** Returns the start code, or the frame code if it does not start with 'N'. */
091  public long readStartCode() throws IOException {
092    byte frameCode = in.readByte();
093    if (frameCode != 'N') {
094      return (long) (frameCode & 0xff);
095    }
096
097    // Otherwise read the remaining 64bit startCode
098    byte[] buffer = new byte[8];
099    buffer[0] = frameCode;
100    readFully(buffer, 1, 7);
101    return (((long) buffer[0] << 56)
102        + ((long) (buffer[1] & 255) << 48)
103        + ((long) (buffer[2] & 255) << 40)
104        + ((long) (buffer[3] & 255) << 32)
105        + ((long) (buffer[4] & 255) << 24)
106        + ((buffer[5] & 255) << 16)
107        + ((buffer[6] & 255) << 8)
108        + ((buffer[7] & 255) << 0));
109  }
110
111  /** Returns the current byte offset in the input stream. */
112  public long offset() {
113    return count.getCount();
114  }
115
116  @Override
117  public void readFully(byte[] b) throws IOException {
118    in.readFully(b);
119  }
120
121  @Override
122  public void readFully(byte[] b, int off, int len) throws IOException {
123    in.readFully(b, off, len);
124  }
125
126  @Override
127  public int skipBytes(int n) throws IOException {
128    return in.skipBytes(n);
129  }
130
131  @Override
132  public boolean readBoolean() throws IOException {
133    return in.readBoolean();
134  }
135
136  @Override
137  public byte readByte() throws IOException {
138    return in.readByte();
139  }
140
141  @Override
142  public int readUnsignedByte() throws IOException {
143    return in.readUnsignedByte();
144  }
145
146  @Override
147  public short readShort() throws IOException {
148    return in.readShort();
149  }
150
151  @Override
152  public int readUnsignedShort() throws IOException {
153    return in.readUnsignedShort();
154  }
155
156  @Override
157  public char readChar() throws IOException {
158    return in.readChar();
159  }
160
161  @Override
162  public int readInt() throws IOException {
163    return in.readInt();
164  }
165
166  @Override
167  public long readLong() throws IOException {
168    return in.readLong();
169  }
170
171  @Override
172  public float readFloat() throws IOException {
173    return in.readFloat();
174  }
175
176  @Override
177  public double readDouble() throws IOException {
178    return in.readDouble();
179  }
180
181  @Override
182  @Deprecated
183  public String readLine() throws IOException {
184    return in.readLine();
185  }
186
187  @Override
188  public String readUTF() throws IOException {
189    return in.readUTF();
190  }
191}