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