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

rlm@10: * Implements the write method of OutputStream. rlm@10: * rlm@10: * @param b the byte to be written. rlm@10: * @exception IOException if an I/O error occurs. rlm@10: * @see java.io.FilterOutputStream#out rlm@10: */ rlm@10: @Override rlm@10: public synchronized void write(int b) throws IOException { rlm@10: out.write(b); rlm@10: incCount(1); rlm@10: } rlm@10: rlm@10: /** rlm@10: * Writes an int to the underlying output stream as four rlm@10: * bytes, high byte first. If no exception is thrown, the counter rlm@10: * written is incremented by 4. rlm@10: * rlm@10: * @param v an int to be written. rlm@10: * @exception IOException if an I/O error occurs. rlm@10: * @see java.io.FilterOutputStream#out rlm@10: */ rlm@10: public void writeInt(int v) throws IOException { rlm@10: out.write((v >>> 0) & 0xff); rlm@10: out.write((v >>> 8) & 0xff); rlm@10: out.write((v >>> 16) & 0xff); rlm@10: out.write((v >>> 24) & 0xff); rlm@10: incCount(4); rlm@10: } rlm@10: rlm@10: /** rlm@10: * Writes an unsigned 32 bit integer value. rlm@10: * rlm@10: * @param v The value rlm@10: * @throws java.io.IOException rlm@10: */ rlm@10: public void writeUInt(long v) throws IOException { rlm@10: out.write((int) ((v >>> 0) & 0xff)); rlm@10: out.write((int) ((v >>> 8) & 0xff)); rlm@10: out.write((int) ((v >>> 16) & 0xff)); rlm@10: out.write((int) ((v >>> 24) & 0xff)); rlm@10: incCount(4); rlm@10: } rlm@10: rlm@10: /** rlm@10: * Writes a signed 16 bit integer value. rlm@10: * rlm@10: * @param v The value rlm@10: * @throws java.io.IOException rlm@10: */ rlm@10: public void writeShort(int v) throws IOException { rlm@10: out.write((int) ((v >>> 0) & 0xff)); rlm@10: out.write((int) ((v >> 8) & 0xff)); rlm@10: incCount(2); rlm@10: } rlm@10: rlm@10: public void writeLong(long v) throws IOException { rlm@10: out.write((int) (v >>> 0) & 0xff); rlm@10: out.write((int) (v >>> 8) & 0xff); rlm@10: out.write((int) (v >>> 16) & 0xff); rlm@10: out.write((int) (v >>> 24) & 0xff); rlm@10: out.write((int) (v >>> 32) & 0xff); rlm@10: out.write((int) (v >>> 40) & 0xff); rlm@10: out.write((int) (v >>> 48) & 0xff); rlm@10: out.write((int) (v >>> 56) & 0xff); rlm@10: incCount(8); rlm@10: } rlm@10: rlm@10: public void writeUShort(int v) throws IOException { rlm@10: out.write((int) ((v >>> 0) & 0xff)); rlm@10: out.write((int) ((v >> 8) & 0xff)); rlm@10: incCount(2); rlm@10: } rlm@10: rlm@10: /** rlm@10: * Increases the written counter by the specified value rlm@10: * until it reaches Long.MAX_VALUE. rlm@10: */ rlm@10: protected void incCount(int value) { rlm@10: long temp = written + value; rlm@10: if (temp < 0) { rlm@10: temp = Long.MAX_VALUE; rlm@10: } rlm@10: written = temp; rlm@10: } rlm@10: rlm@10: /** rlm@10: * Returns the current value of the counter written, rlm@10: * the number of bytes written to this data output stream so far. rlm@10: * If the counter overflows, it will be wrapped to Integer.MAX_VALUE. rlm@10: * rlm@10: * @return the value of the written field. rlm@10: * @see java.io.DataOutputStream#written rlm@10: */ rlm@10: public final long size() { rlm@10: return written; rlm@10: } rlm@10: rlm@10: /** rlm@10: * Sets the value of the counter written to 0. rlm@10: */ rlm@10: public void clearCount() { rlm@10: written = 0; rlm@10: } rlm@10: rlm@10: @Override rlm@10: public void close() throws IOException { rlm@10: if (forwardFlushAndClose) { rlm@10: super.close(); rlm@10: } rlm@10: } rlm@10: rlm@10: @Override rlm@10: public void flush() throws IOException { rlm@10: if (forwardFlushAndClose) { rlm@10: super.flush(); rlm@10: } rlm@10: } rlm@10: rlm@10: }