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:
019: package org.apache.tools.ant.util;
020:
021: import java.io.ByteArrayOutputStream;
022: import java.io.IOException;
023: import java.io.OutputStream;
024:
025: /**
026: * Invokes {@link #processLine processLine} whenever a full line has
027: * been written to this stream.
028: *
029: * <p>Tries to be smart about line separators.</p>
030: */
031: public abstract class LineOrientedOutputStream extends OutputStream {
032:
033: /** Initial buffer size. */
034: private static final int INTIAL_SIZE = 132;
035:
036: /** Carriage return */
037: private static final int CR = 0x0d;
038:
039: /** Linefeed */
040: private static final int LF = 0x0a;
041:
042: private ByteArrayOutputStream buffer = new ByteArrayOutputStream(
043: INTIAL_SIZE);
044: private boolean skip = false;
045:
046: /**
047: * Write the data to the buffer and flush the buffer, if a line
048: * separator is detected.
049: *
050: * @param cc data to log (byte).
051: * @throws IOException if there is an error.
052: */
053: public final void write(int cc) throws IOException {
054: final byte c = (byte) cc;
055: if ((c == LF) || (c == CR)) {
056: if (!skip) {
057: processBuffer();
058: }
059: } else {
060: buffer.write(cc);
061: }
062: skip = (c == CR);
063: }
064:
065: /**
066: * Flush this log stream
067: * @throws IOException if there is an error.
068: */
069: public final void flush() throws IOException {
070: if (buffer.size() > 0) {
071: processBuffer();
072: }
073: }
074:
075: /**
076: * Converts the buffer to a string and sends it to
077: * <code>processLine</code>
078: * @throws IOException if there is an error.
079: */
080: protected void processBuffer() throws IOException {
081: try {
082: processLine(buffer.toString());
083: } finally {
084: buffer.reset();
085: }
086: }
087:
088: /**
089: * Processes a line.
090: *
091: * @param line the line to log.
092: * @throws IOException if there is an error.
093: */
094: protected abstract void processLine(String line) throws IOException;
095:
096: /**
097: * Writes all remaining
098: * @throws IOException if there is an error.
099: */
100: public final void close() throws IOException {
101: if (buffer.size() > 0) {
102: processBuffer();
103: }
104: super .close();
105: }
106:
107: /**
108: * Write a block of characters to the output stream
109: *
110: * @param b the array containing the data
111: * @param off the offset into the array where data starts
112: * @param len the length of block
113: *
114: * @throws IOException if the data cannot be written into the stream.
115: */
116: public final void write(byte[] b, int off, int len)
117: throws IOException {
118: // find the line breaks and pass other chars through in blocks
119: int offset = off;
120: int blockStartOffset = offset;
121: int remaining = len;
122: while (remaining > 0) {
123: while (remaining > 0 && b[offset] != LF && b[offset] != CR) {
124: offset++;
125: remaining--;
126: }
127: // either end of buffer or a line separator char
128: int blockLength = offset - blockStartOffset;
129: if (blockLength > 0) {
130: buffer.write(b, blockStartOffset, blockLength);
131: }
132: while (remaining > 0
133: && (b[offset] == LF || b[offset] == CR)) {
134: write(b[offset]);
135: offset++;
136: remaining--;
137: }
138: blockStartOffset = offset;
139: }
140: }
141:
142: }
|