rlm@10
|
1 /**
|
rlm@10
|
2 * @(#)DataChunkOutputStream.java 1.1 2011-01-17
|
rlm@10
|
3 *
|
rlm@10
|
4 * Copyright (c) 2008-2011 Werner Randelshofer, Immensee, Switzerland.
|
rlm@10
|
5 * All rights reserved.
|
rlm@10
|
6 *
|
rlm@10
|
7 * You may not use, copy or modify this file, except in compliance with the
|
rlm@10
|
8 * license agreement you entered into with Werner Randelshofer.
|
rlm@10
|
9 * For details see accompanying license terms.
|
rlm@10
|
10 */
|
rlm@10
|
11 package ca.randelshofer;
|
rlm@10
|
12
|
rlm@10
|
13 import java.io.*;
|
rlm@10
|
14
|
rlm@10
|
15 /**
|
rlm@10
|
16 * This output stream filter supports common data types used inside
|
rlm@10
|
17 * of AVI RIFF Data Chunks.
|
rlm@10
|
18 *
|
rlm@10
|
19 * @author Werner Randelshofer
|
rlm@10
|
20 * @version 1.1 2011-01-17 Adds functionality for blocking flush and close.
|
rlm@10
|
21 * <br>1.0.1 2010-04-05 Removed unused constants.
|
rlm@10
|
22 * <br>1.0 2008-08-11 Created.
|
rlm@10
|
23 */
|
rlm@10
|
24 public class DataChunkOutputStream extends FilterOutputStream {
|
rlm@10
|
25
|
rlm@10
|
26 /**
|
rlm@10
|
27 * The number of bytes written to the data output stream so far.
|
rlm@10
|
28 * If this counter overflows, it will be wrapped to Integer.MAX_VALUE.
|
rlm@10
|
29 */
|
rlm@10
|
30 protected long written;
|
rlm@10
|
31
|
rlm@10
|
32 /** Whether flush and close request shall be forwarded to underlying stream.*/
|
rlm@10
|
33 private boolean forwardFlushAndClose;
|
rlm@10
|
34
|
rlm@10
|
35 public DataChunkOutputStream(OutputStream out) {
|
rlm@10
|
36 this(out,true);
|
rlm@10
|
37 }
|
rlm@10
|
38 public DataChunkOutputStream(OutputStream out, boolean forwardFlushAndClose) {
|
rlm@10
|
39 super(out);
|
rlm@10
|
40 this.forwardFlushAndClose=forwardFlushAndClose;
|
rlm@10
|
41 }
|
rlm@10
|
42
|
rlm@10
|
43 /**
|
rlm@10
|
44 * Writes an chunk type identifier (4 bytes).
|
rlm@10
|
45 * @param s A string with a length of 4 characters.
|
rlm@10
|
46 */
|
rlm@10
|
47 public void writeType(String s) throws IOException {
|
rlm@10
|
48 if (s.length() != 4) {
|
rlm@10
|
49 throw new IllegalArgumentException("type string must have 4 characters");
|
rlm@10
|
50 }
|
rlm@10
|
51
|
rlm@10
|
52 try {
|
rlm@10
|
53 out.write(s.getBytes("ASCII"), 0, 4);
|
rlm@10
|
54 incCount(4);
|
rlm@10
|
55 } catch (UnsupportedEncodingException e) {
|
rlm@10
|
56 throw new InternalError(e.toString());
|
rlm@10
|
57 }
|
rlm@10
|
58 }
|
rlm@10
|
59
|
rlm@10
|
60 /**
|
rlm@10
|
61 * Writes out a <code>byte</code> to the underlying output stream as
|
rlm@10
|
62 * a 1-byte value. If no exception is thrown, the counter
|
rlm@10
|
63 * <code>written</code> is incremented by <code>1</code>.
|
rlm@10
|
64 *
|
rlm@10
|
65 * @param v a <code>byte</code> value to be written.
|
rlm@10
|
66 * @exception IOException if an I/O error occurs.
|
rlm@10
|
67 * @see java.io.FilterOutputStream#out
|
rlm@10
|
68 */
|
rlm@10
|
69 public final void writeByte(int v) throws IOException {
|
rlm@10
|
70 out.write(v);
|
rlm@10
|
71 incCount(1);
|
rlm@10
|
72 }
|
rlm@10
|
73
|
rlm@10
|
74 /**
|
rlm@10
|
75 * Writes <code>len</code> bytes from the specified byte array
|
rlm@10
|
76 * starting at offset <code>off</code> to the underlying output stream.
|
rlm@10
|
77 * If no exception is thrown, the counter <code>written</code> is
|
rlm@10
|
78 * incremented by <code>len</code>.
|
rlm@10
|
79 *
|
rlm@10
|
80 * @param b the data.
|
rlm@10
|
81 * @param off the start offset in the data.
|
rlm@10
|
82 * @param len the number of bytes to write.
|
rlm@10
|
83 * @exception IOException if an I/O error occurs.
|
rlm@10
|
84 * @see java.io.FilterOutputStream#out
|
rlm@10
|
85 */
|
rlm@10
|
86 @Override
|
rlm@10
|
87 public synchronized void write(byte b[], int off, int len)
|
rlm@10
|
88 throws IOException {
|
rlm@10
|
89 out.write(b, off, len);
|
rlm@10
|
90 incCount(len);
|
rlm@10
|
91 }
|
rlm@10
|
92
|
rlm@10
|
93 /**
|
rlm@10
|
94 * Writes the specified byte (the low eight bits of the argument
|
rlm@10
|
95 * <code>b</code>) to the underlying output stream. If no exception
|
rlm@10
|
96 * is thrown, the counter <code>written</code> is incremented by
|
rlm@10
|
97 * <code>1</code>.
|
rlm@10
|
98 * <p>
|
rlm@10
|
99 * Implements the <code>write</code> method of <code>OutputStream</code>.
|
rlm@10
|
100 *
|
rlm@10
|
101 * @param b the <code>byte</code> to be written.
|
rlm@10
|
102 * @exception IOException if an I/O error occurs.
|
rlm@10
|
103 * @see java.io.FilterOutputStream#out
|
rlm@10
|
104 */
|
rlm@10
|
105 @Override
|
rlm@10
|
106 public synchronized void write(int b) throws IOException {
|
rlm@10
|
107 out.write(b);
|
rlm@10
|
108 incCount(1);
|
rlm@10
|
109 }
|
rlm@10
|
110
|
rlm@10
|
111 /**
|
rlm@10
|
112 * Writes an <code>int</code> to the underlying output stream as four
|
rlm@10
|
113 * bytes, high byte first. If no exception is thrown, the counter
|
rlm@10
|
114 * <code>written</code> is incremented by <code>4</code>.
|
rlm@10
|
115 *
|
rlm@10
|
116 * @param v an <code>int</code> to be written.
|
rlm@10
|
117 * @exception IOException if an I/O error occurs.
|
rlm@10
|
118 * @see java.io.FilterOutputStream#out
|
rlm@10
|
119 */
|
rlm@10
|
120 public void writeInt(int v) throws IOException {
|
rlm@10
|
121 out.write((v >>> 0) & 0xff);
|
rlm@10
|
122 out.write((v >>> 8) & 0xff);
|
rlm@10
|
123 out.write((v >>> 16) & 0xff);
|
rlm@10
|
124 out.write((v >>> 24) & 0xff);
|
rlm@10
|
125 incCount(4);
|
rlm@10
|
126 }
|
rlm@10
|
127
|
rlm@10
|
128 /**
|
rlm@10
|
129 * Writes an unsigned 32 bit integer value.
|
rlm@10
|
130 *
|
rlm@10
|
131 * @param v The value
|
rlm@10
|
132 * @throws java.io.IOException
|
rlm@10
|
133 */
|
rlm@10
|
134 public void writeUInt(long v) throws IOException {
|
rlm@10
|
135 out.write((int) ((v >>> 0) & 0xff));
|
rlm@10
|
136 out.write((int) ((v >>> 8) & 0xff));
|
rlm@10
|
137 out.write((int) ((v >>> 16) & 0xff));
|
rlm@10
|
138 out.write((int) ((v >>> 24) & 0xff));
|
rlm@10
|
139 incCount(4);
|
rlm@10
|
140 }
|
rlm@10
|
141
|
rlm@10
|
142 /**
|
rlm@10
|
143 * Writes a signed 16 bit integer value.
|
rlm@10
|
144 *
|
rlm@10
|
145 * @param v The value
|
rlm@10
|
146 * @throws java.io.IOException
|
rlm@10
|
147 */
|
rlm@10
|
148 public void writeShort(int v) throws IOException {
|
rlm@10
|
149 out.write((int) ((v >>> 0) & 0xff));
|
rlm@10
|
150 out.write((int) ((v >> 8) & 0xff));
|
rlm@10
|
151 incCount(2);
|
rlm@10
|
152 }
|
rlm@10
|
153
|
rlm@10
|
154 public void writeLong(long v) throws IOException {
|
rlm@10
|
155 out.write((int) (v >>> 0) & 0xff);
|
rlm@10
|
156 out.write((int) (v >>> 8) & 0xff);
|
rlm@10
|
157 out.write((int) (v >>> 16) & 0xff);
|
rlm@10
|
158 out.write((int) (v >>> 24) & 0xff);
|
rlm@10
|
159 out.write((int) (v >>> 32) & 0xff);
|
rlm@10
|
160 out.write((int) (v >>> 40) & 0xff);
|
rlm@10
|
161 out.write((int) (v >>> 48) & 0xff);
|
rlm@10
|
162 out.write((int) (v >>> 56) & 0xff);
|
rlm@10
|
163 incCount(8);
|
rlm@10
|
164 }
|
rlm@10
|
165
|
rlm@10
|
166 public void writeUShort(int v) throws IOException {
|
rlm@10
|
167 out.write((int) ((v >>> 0) & 0xff));
|
rlm@10
|
168 out.write((int) ((v >> 8) & 0xff));
|
rlm@10
|
169 incCount(2);
|
rlm@10
|
170 }
|
rlm@10
|
171
|
rlm@10
|
172 /**
|
rlm@10
|
173 * Increases the written counter by the specified value
|
rlm@10
|
174 * until it reaches Long.MAX_VALUE.
|
rlm@10
|
175 */
|
rlm@10
|
176 protected void incCount(int value) {
|
rlm@10
|
177 long temp = written + value;
|
rlm@10
|
178 if (temp < 0) {
|
rlm@10
|
179 temp = Long.MAX_VALUE;
|
rlm@10
|
180 }
|
rlm@10
|
181 written = temp;
|
rlm@10
|
182 }
|
rlm@10
|
183
|
rlm@10
|
184 /**
|
rlm@10
|
185 * Returns the current value of the counter <code>written</code>,
|
rlm@10
|
186 * the number of bytes written to this data output stream so far.
|
rlm@10
|
187 * If the counter overflows, it will be wrapped to Integer.MAX_VALUE.
|
rlm@10
|
188 *
|
rlm@10
|
189 * @return the value of the <code>written</code> field.
|
rlm@10
|
190 * @see java.io.DataOutputStream#written
|
rlm@10
|
191 */
|
rlm@10
|
192 public final long size() {
|
rlm@10
|
193 return written;
|
rlm@10
|
194 }
|
rlm@10
|
195
|
rlm@10
|
196 /**
|
rlm@10
|
197 * Sets the value of the counter <code>written</code> to 0.
|
rlm@10
|
198 */
|
rlm@10
|
199 public void clearCount() {
|
rlm@10
|
200 written = 0;
|
rlm@10
|
201 }
|
rlm@10
|
202
|
rlm@10
|
203 @Override
|
rlm@10
|
204 public void close() throws IOException {
|
rlm@10
|
205 if (forwardFlushAndClose) {
|
rlm@10
|
206 super.close();
|
rlm@10
|
207 }
|
rlm@10
|
208 }
|
rlm@10
|
209
|
rlm@10
|
210 @Override
|
rlm@10
|
211 public void flush() throws IOException {
|
rlm@10
|
212 if (forwardFlushAndClose) {
|
rlm@10
|
213 super.flush();
|
rlm@10
|
214 }
|
rlm@10
|
215 }
|
rlm@10
|
216
|
rlm@10
|
217 }
|