001: // You can redistribute this software and/or modify it under the terms of
002: // the Ozone Library License version 1 published by ozone-db.org.
003: //
004: // The original code and portions created by SMB are
005: // Copyright (C) 1997-@year@ by SMB GmbH. All rights reserved.
006: //
007: // $Id: ChunkOutputStream.java,v 1.1 2001/12/18 10:31:31 per_nyfelt Exp $
008:
009: package org.ozoneDB.xml.util;
010:
011: import java.io.OutputStream;
012: import java.io.IOException;
013: import java.io.Externalizable;
014: import java.io.Serializable;
015: import java.io.ObjectInputStream;
016: import java.io.ObjectOutputStream;
017:
018: /**
019: */
020: public final class ChunkOutputStream extends OutputStream implements
021: Serializable { //Externalizable {
022:
023: /**
024: * the output stream has not yet exceeded its initial size.
025: */
026: public final static byte STATE_NORMAL = 0;
027:
028: /**
029: * the output stream has exceeded its initial size.
030: */
031: public final static byte STATE_OVERFLOW = 1;
032:
033: /**
034: * true if this is the last chunk in a sequence of chunks, false otherwise.
035: */
036: public boolean endFlag = false;
037:
038: /**
039: * The buffer where data is stored.
040: */
041: protected byte[] buf;
042:
043: /**
044: * The number of valid bytes in the buffer.
045: */
046: protected int count;
047:
048: /**
049: * the state of this output stream.
050: */
051: private byte state;
052:
053: /**
054: * The initial size of this output stream
055: */
056: private int initialSize;
057:
058: /**
059: * The amount of bytes by which the buffer will be increased if it overflows.
060: */
061: private int increase;
062:
063: /**
064: * Creates a new byte array output stream. The buffer capacity is initially
065: * 1000 bytes. Its size increases by 100 bytes if necessary.
066: */
067: public ChunkOutputStream() {
068: this (1000, 100);
069: }
070:
071: /**
072: * Creates a new byte array output stream, with a buffer capacity of
073: * the specified size in bytes. Its size increases by 100 bytes if necessary.
074: *
075: * @param size the initial size. exceeding this size causes the
076: * stream to enter state {@link #STATE_OVERFLOW}.
077: * @exception IllegalArgumentException if size is negative.
078: */
079: public ChunkOutputStream(int size) {
080: this (size, 100);
081: }
082:
083: /**
084: * Creates a new byte array output stream, with a buffer capacity of
085: * the specified size in bytes. Its size increases by the specified increase
086: * in bytes if necessary.
087: *
088: * @param overflowSize the initial size. exceeding this size causes the
089: * stream to enter state {@link #STATE_OVERFLOW}.
090: * @param increase the amount of bytes by which the stream will be incre
091: * @exception IllegalArgumentException if <code>size</code> is negative or
092: * <code>increase</code> is less or equal 0.
093: */
094: public ChunkOutputStream(int size, int increase) {
095: if (size < 0) {
096: throw new IllegalArgumentException(
097: "Negative initial size: " + size);
098: }
099: if (increase <= 0) {
100: throw new IllegalArgumentException(
101: "Increase less or equal 0: " + size);
102: }
103: this .buf = new byte[size + increase];
104: this .increase = increase;
105: this .initialSize = size;
106: this .state = ChunkOutputStream.STATE_NORMAL;
107: this .count = 0;
108: }
109:
110: public void writeObject(ObjectOutputStream out) throws IOException {
111: out.writeBoolean(endFlag);
112: out.writeInt(this .increase);
113: out.writeInt(this .initialSize);
114: out.writeByte(this .state);
115: out.writeInt(this .count);
116: out.write(this .buf, 0, this .count);
117: }
118:
119: public void readObject(ObjectInputStream in) throws IOException,
120: ClassNotFoundException {
121: this .endFlag = in.readBoolean();
122: this .increase = in.readInt();
123: this .initialSize = in.readInt();
124: this .state = in.readByte();
125: this .count = in.readInt();
126: this .buf = new byte[this .initialSize + this .increase];
127: in.read(this .buf, 0, this .count);
128: }
129:
130: // output stream only methods
131:
132: /**
133: * Writes the specified byte to this byte array output stream.
134: *
135: * @param b the byte to be written.
136: */
137: public final void write(int b) {
138:
139: int newcount = this .count + 1;
140: if (newcount > this .buf.length) {
141: byte[] newbuf = new byte[this .count + this .increase];
142: System.arraycopy(this .buf, 0, newbuf, 0, this .count);
143: this .buf = newbuf;
144: this .state = ChunkOutputStream.STATE_OVERFLOW;
145: }
146: this .buf[this .count] = (byte) b;
147: this .count = newcount;
148: }
149:
150: /**
151: * Writes <code>len</code> bytes from the specified byte array
152: * starting at offset <code>off</code> to this byte array output stream.
153: *
154: * @param b the data.
155: * @param off the start offset in the data.
156: * @param len the number of bytes to write.
157: */
158: public final void write(byte[] b, int off, int len) {
159: if (off < 0 || off > b.length || len < 0
160: || off + len > b.length || off + len < 0) {
161: throw new IndexOutOfBoundsException();
162: } else {
163: if (len == 0) {
164: return;
165: }
166: }
167:
168: int newCount = this .count + len;
169: if (newCount > this .buf.length) {
170: int newLength = this .buf.length + increase;
171: byte[] newbuf = new byte[(newLength >= newCount) ? newLength
172: : newCount];
173: System.arraycopy(this .buf, 0, newbuf, 0, this .count);
174: this .buf = newbuf;
175: this .state = ChunkOutputStream.STATE_OVERFLOW;
176: }
177:
178: System.arraycopy(b, off, this .buf, this .count, len);
179: this .count = newCount;
180: }
181:
182: /**
183: * Writes the complete contents of this byte array output stream to
184: * the specified output stream argument, as if by calling the output
185: * stream's write method using <code>out.write(buf, 0, count)</code>.
186: *
187: * @param out the output stream to which to write the data.
188: * @exception IOException if an I/O error occurs.
189: */
190: public final void writeTo(OutputStream out) throws IOException {
191: out.write(this .buf, 0, this .count);
192: }
193:
194: /**
195: * Resets the <code>count</code> field of this byte array output
196: * stream to zero, so that all currently accumulated output in the
197: * ouput stream is discarded. The output stream can be used again,
198: * reusing the already allocated buffer space.
199: *
200: * @see java.io.ByteArrayInputStream#count
201: */
202: public final void reset() {
203: this .buf = new byte[initialSize + increase];
204: this .state = ChunkOutputStream.STATE_NORMAL;
205: this .count = 0;
206: }
207:
208: /**
209: * The number of valid bytes in this stream.
210: */
211: public final int size() {
212: return this .count;
213: }
214:
215: /**
216: * Creates a newly allocated byte array. Its size is the current
217: * size of this output stream and the valid contents of the buffer
218: * have been copied into it.
219: *
220: * @return the current contents of this output stream, as a byte array.
221: * @see java.io.ByteArrayOutputStream#size()
222: */
223: public final byte[] toByteArray() {
224: byte[] newbuf = new byte[this .count];
225: System.arraycopy(this .buf, 0, newbuf, 0, this .count);
226: return newbuf;
227: }
228:
229: /**
230: * @return the state of this output stream
231: */
232: public final byte getState() {
233: return this .state;
234: }
235:
236: /**
237: * marks this chunk as the last in a sequence of chunks
238: */
239: public final void setEndFlag() {
240: this .endFlag = true;
241: }
242:
243: /**
244: * @return true, if this chunk is the last in a sequence of chunks
245: */
246: public final boolean getEndFlag() {
247: return this.endFlag;
248: }
249: }
|