001: /* ====================================================================
002: Licensed to the Apache Software Foundation (ASF) under one or more
003: contributor license agreements. See the NOTICE file distributed with
004: this work for additional information regarding copyright ownership.
005: The ASF licenses this file to You under the Apache License, Version 2.0
006: (the "License"); you may not use this file except in compliance with
007: the License. You may obtain a copy of the License at
008:
009: http://www.apache.org/licenses/LICENSE-2.0
010:
011: Unless required by applicable law or agreed to in writing, software
012: distributed under the License is distributed on an "AS IS" BASIS,
013: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: See the License for the specific language governing permissions and
015: limitations under the License.
016: ==================================================================== */
017:
018: package org.apache.poi.poifs.filesystem;
019:
020: import java.io.*;
021:
022: import java.util.*;
023:
024: /**
025: * This class provides a wrapper over an OutputStream so that Document
026: * writers can't accidently go over their size limits
027: *
028: * @author Marc Johnson (mjohnson at apache dot org)
029: */
030:
031: public class DocumentOutputStream extends OutputStream {
032: private OutputStream stream;
033: private int limit;
034: private int written;
035:
036: /**
037: * Create a DocumentOutputStream
038: *
039: * @param stream the OutputStream to which the data is actually
040: * read
041: * @param limit the maximum number of bytes that can be written
042: */
043:
044: DocumentOutputStream(final OutputStream stream, final int limit) {
045: this .stream = stream;
046: this .limit = limit;
047: this .written = 0;
048: }
049:
050: /**
051: * Writes the specified byte to this output stream. The general
052: * contract for write is that one byte is written to the output
053: * stream. The byte to be written is the eight low-order bits of
054: * the argument b. The 24 high-order bits of b are ignored.
055: *
056: * @param b the byte.
057: * @exception IOException if an I/O error occurs. In particular,
058: * an IOException may be thrown if the
059: * output stream has been closed, or if the
060: * writer tries to write too much data.
061: */
062:
063: public void write(final int b) throws IOException {
064: limitCheck(1);
065: stream.write(b);
066: }
067:
068: /**
069: * Writes b.length bytes from the specified byte array
070: * to this output stream.
071: *
072: * @param b the data.
073: * @exception IOException if an I/O error occurs.
074: */
075:
076: public void write(final byte b[]) throws IOException {
077: write(b, 0, b.length);
078: }
079:
080: /**
081: * Writes len bytes from the specified byte array starting at
082: * offset off to this output stream. The general contract for
083: * write(b, off, len) is that some of the bytes in the array b are
084: * written to the output stream in order; element b[off] is the
085: * first byte written and b[off+len-1] is the last byte written by
086: * this operation.<p>
087: * If b is null, a NullPointerException is thrown.<p>
088: * If off is negative, or len is negative, or off+len is greater
089: * than the length of the array b, then an
090: * IndexOutOfBoundsException is thrown.
091: *
092: * @param b the data.
093: * @param off the start offset in the data.
094: * @param len the number of bytes to write.
095: * @exception IOException if an I/O error occurs. In particular,
096: * an IOException</code> is thrown if the
097: * output stream is closed or if the writer
098: * tries to write too many bytes.
099: */
100:
101: public void write(final byte b[], final int off, final int len)
102: throws IOException {
103: limitCheck(len);
104: stream.write(b, off, len);
105: }
106:
107: /**
108: * Flushes this output stream and forces any buffered output bytes
109: * to be written out.
110: *
111: * @exception IOException if an I/O error occurs.
112: */
113:
114: public void flush() throws IOException {
115: stream.flush();
116: }
117:
118: /**
119: * Closes this output stream and releases any system resources
120: * associated with this stream. The general contract of close is
121: * that it closes the output stream. A closed stream cannot
122: * perform output operations and cannot be reopened.
123: *
124: * @exception IOException if an I/O error occurs.
125: */
126:
127: public void close() throws IOException {
128:
129: // ignore this call
130: }
131:
132: /**
133: * write the rest of the document's data (fill in at the end)
134: *
135: * @param totalLimit the actual number of bytes the corresponding
136: * document must fill
137: * @param fill the byte to fill remaining space with
138: *
139: * @exception IOException on I/O error
140: */
141:
142: void writeFiller(final int totalLimit, final byte fill)
143: throws IOException {
144: if (totalLimit > written) {
145: byte[] filler = new byte[totalLimit - written];
146:
147: Arrays.fill(filler, fill);
148: stream.write(filler);
149: }
150: }
151:
152: private void limitCheck(final int toBeWritten) throws IOException {
153: if ((written + toBeWritten) > limit) {
154: throw new IOException("tried to write too much data");
155: }
156: written += toBeWritten;
157: }
158: } // end public class DocumentOutputStream
|