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: }