rlm@3: /**
rlm@3: * @(#)DataChunkOutputStream.java 1.1 2011-01-17
rlm@3: *
rlm@3: * Copyright (c) 2008-2011 Werner Randelshofer, Immensee, Switzerland.
rlm@3: * All rights reserved.
rlm@3: *
rlm@3: * You may not use, copy or modify this file, except in compliance with the
rlm@3: * license agreement you entered into with Werner Randelshofer.
rlm@3: * For details see accompanying license terms.
rlm@3: */
rlm@3: package com.aurellem.capture;
rlm@3:
rlm@3: import java.io.*;
rlm@3:
rlm@3: /**
rlm@3: * This output stream filter supports common data types used inside
rlm@3: * of AVI RIFF Data Chunks.
rlm@3: *
rlm@3: * @author Werner Randelshofer
rlm@3: * @version 1.1 2011-01-17 Adds functionality for blocking flush and close.
rlm@3: *
1.0.1 2010-04-05 Removed unused constants.
rlm@3: *
1.0 2008-08-11 Created.
rlm@3: */
rlm@3: public class DataChunkOutputStream extends FilterOutputStream {
rlm@3:
rlm@3: /**
rlm@3: * The number of bytes written to the data output stream so far.
rlm@3: * If this counter overflows, it will be wrapped to Integer.MAX_VALUE.
rlm@3: */
rlm@3: protected long written;
rlm@3:
rlm@3: /** Whether flush and close request shall be forwarded to underlying stream.*/
rlm@3: private boolean forwardFlushAndClose;
rlm@3:
rlm@3: public DataChunkOutputStream(OutputStream out) {
rlm@3: this(out,true);
rlm@3: }
rlm@3: public DataChunkOutputStream(OutputStream out, boolean forwardFlushAndClose) {
rlm@3: super(out);
rlm@3: this.forwardFlushAndClose=forwardFlushAndClose;
rlm@3: }
rlm@3:
rlm@3: /**
rlm@3: * Writes an chunk type identifier (4 bytes).
rlm@3: * @param s A string with a length of 4 characters.
rlm@3: */
rlm@3: public void writeType(String s) throws IOException {
rlm@3: if (s.length() != 4) {
rlm@3: throw new IllegalArgumentException("type string must have 4 characters");
rlm@3: }
rlm@3:
rlm@3: try {
rlm@3: out.write(s.getBytes("ASCII"), 0, 4);
rlm@3: incCount(4);
rlm@3: } catch (UnsupportedEncodingException e) {
rlm@3: throw new InternalError(e.toString());
rlm@3: }
rlm@3: }
rlm@3:
rlm@3: /**
rlm@3: * Writes out a byte
to the underlying output stream as
rlm@3: * a 1-byte value. If no exception is thrown, the counter
rlm@3: * written
is incremented by 1
.
rlm@3: *
rlm@3: * @param v a byte
value to be written.
rlm@3: * @exception IOException if an I/O error occurs.
rlm@3: * @see java.io.FilterOutputStream#out
rlm@3: */
rlm@3: public final void writeByte(int v) throws IOException {
rlm@3: out.write(v);
rlm@3: incCount(1);
rlm@3: }
rlm@3:
rlm@3: /**
rlm@3: * Writes len
bytes from the specified byte array
rlm@3: * starting at offset off
to the underlying output stream.
rlm@3: * If no exception is thrown, the counter written
is
rlm@3: * incremented by len
.
rlm@3: *
rlm@3: * @param b the data.
rlm@3: * @param off the start offset in the data.
rlm@3: * @param len the number of bytes to write.
rlm@3: * @exception IOException if an I/O error occurs.
rlm@3: * @see java.io.FilterOutputStream#out
rlm@3: */
rlm@3: @Override
rlm@3: public synchronized void write(byte b[], int off, int len)
rlm@3: throws IOException {
rlm@3: out.write(b, off, len);
rlm@3: incCount(len);
rlm@3: }
rlm@3:
rlm@3: /**
rlm@3: * Writes the specified byte (the low eight bits of the argument
rlm@3: * b
) to the underlying output stream. If no exception
rlm@3: * is thrown, the counter written
is incremented by
rlm@3: * 1
.
rlm@3: *
rlm@3: * Implements the write
method of OutputStream
.
rlm@3: *
rlm@3: * @param b the byte
to be written.
rlm@3: * @exception IOException if an I/O error occurs.
rlm@3: * @see java.io.FilterOutputStream#out
rlm@3: */
rlm@3: @Override
rlm@3: public synchronized void write(int b) throws IOException {
rlm@3: out.write(b);
rlm@3: incCount(1);
rlm@3: }
rlm@3:
rlm@3: /**
rlm@3: * Writes an int
to the underlying output stream as four
rlm@3: * bytes, high byte first. If no exception is thrown, the counter
rlm@3: * written
is incremented by 4
.
rlm@3: *
rlm@3: * @param v an int
to be written.
rlm@3: * @exception IOException if an I/O error occurs.
rlm@3: * @see java.io.FilterOutputStream#out
rlm@3: */
rlm@3: public void writeInt(int v) throws IOException {
rlm@3: out.write((v >>> 0) & 0xff);
rlm@3: out.write((v >>> 8) & 0xff);
rlm@3: out.write((v >>> 16) & 0xff);
rlm@3: out.write((v >>> 24) & 0xff);
rlm@3: incCount(4);
rlm@3: }
rlm@3:
rlm@3: /**
rlm@3: * Writes an unsigned 32 bit integer value.
rlm@3: *
rlm@3: * @param v The value
rlm@3: * @throws java.io.IOException
rlm@3: */
rlm@3: public void writeUInt(long v) throws IOException {
rlm@3: out.write((int) ((v >>> 0) & 0xff));
rlm@3: out.write((int) ((v >>> 8) & 0xff));
rlm@3: out.write((int) ((v >>> 16) & 0xff));
rlm@3: out.write((int) ((v >>> 24) & 0xff));
rlm@3: incCount(4);
rlm@3: }
rlm@3:
rlm@3: /**
rlm@3: * Writes a signed 16 bit integer value.
rlm@3: *
rlm@3: * @param v The value
rlm@3: * @throws java.io.IOException
rlm@3: */
rlm@3: public void writeShort(int v) throws IOException {
rlm@3: out.write((int) ((v >>> 0) & 0xff));
rlm@3: out.write((int) ((v >> 8) & 0xff));
rlm@3: incCount(2);
rlm@3: }
rlm@3:
rlm@3: public void writeLong(long v) throws IOException {
rlm@3: out.write((int) (v >>> 0) & 0xff);
rlm@3: out.write((int) (v >>> 8) & 0xff);
rlm@3: out.write((int) (v >>> 16) & 0xff);
rlm@3: out.write((int) (v >>> 24) & 0xff);
rlm@3: out.write((int) (v >>> 32) & 0xff);
rlm@3: out.write((int) (v >>> 40) & 0xff);
rlm@3: out.write((int) (v >>> 48) & 0xff);
rlm@3: out.write((int) (v >>> 56) & 0xff);
rlm@3: incCount(8);
rlm@3: }
rlm@3:
rlm@3: public void writeUShort(int v) throws IOException {
rlm@3: out.write((int) ((v >>> 0) & 0xff));
rlm@3: out.write((int) ((v >> 8) & 0xff));
rlm@3: incCount(2);
rlm@3: }
rlm@3:
rlm@3: /**
rlm@3: * Increases the written counter by the specified value
rlm@3: * until it reaches Long.MAX_VALUE.
rlm@3: */
rlm@3: protected void incCount(int value) {
rlm@3: long temp = written + value;
rlm@3: if (temp < 0) {
rlm@3: temp = Long.MAX_VALUE;
rlm@3: }
rlm@3: written = temp;
rlm@3: }
rlm@3:
rlm@3: /**
rlm@3: * Returns the current value of the counter written
,
rlm@3: * the number of bytes written to this data output stream so far.
rlm@3: * If the counter overflows, it will be wrapped to Integer.MAX_VALUE.
rlm@3: *
rlm@3: * @return the value of the written
field.
rlm@3: * @see java.io.DataOutputStream#written
rlm@3: */
rlm@3: public final long size() {
rlm@3: return written;
rlm@3: }
rlm@3:
rlm@3: /**
rlm@3: * Sets the value of the counter written
to 0.
rlm@3: */
rlm@3: public void clearCount() {
rlm@3: written = 0;
rlm@3: }
rlm@3:
rlm@3: @Override
rlm@3: public void close() throws IOException {
rlm@3: if (forwardFlushAndClose) {
rlm@3: super.close();
rlm@3: }
rlm@3: }
rlm@3:
rlm@3: @Override
rlm@3: public void flush() throws IOException {
rlm@3: if (forwardFlushAndClose) {
rlm@3: super.flush();
rlm@3: }
rlm@3: }
rlm@3:
rlm@3: }