/*
* Copyright (C) 2014 RoboVM AB
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/gpl-2.0.html>.
*/
package org.robovm.compiler.util.io;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import org.apache.commons.io.IOUtils;
/**
* Reads from one {@link InputStream} and writes to an {@link OutputStream}
* looking for a pattern in the in data.
*/
public abstract class FilteringStreamProxy extends Thread {
private final int bufferSize;
protected final InputStream in;
protected final OutputStream out;
public FilteringStreamProxy(InputStream in, OutputStream out) {
this(4096, in, out);
}
public FilteringStreamProxy(int bufferSize, InputStream in, OutputStream out) {
this.bufferSize = bufferSize;
this.in = in;
this.out = out;
setDaemon(true);
setName(FilteringStreamProxy.class.getSimpleName() + "Thread["
+ getClass().getSimpleName() + "]");
}
/**
* Searches for a pattern in the specified buffer. Returns {@code true} when
* found. It's the responsibility of this method to write any buffered bytes
* to the specified {@link OutputStream} once the pattern has been found.
*/
protected abstract boolean findPattern(byte[] b, int length, OutputStream out)
throws IOException;
private byte[] ensureBufferSize(byte[] buffer, int requiredLength) {
if (buffer.length < requiredLength) {
byte[] newBuffer = new byte[buffer.length * 2];
System.arraycopy(buffer, 0, newBuffer, 0, buffer.length);
buffer = newBuffer;
}
return buffer;
}
public void run() {
try {
boolean eof = false;
// Read byte by byte until we find the pattern we're looking for.
byte[] buffer = new byte[bufferSize];
int pos = 0;
while (!eof && !isInterrupted() && !shouldStop()) {
int b = in.read();
if (b == -1) {
eof = true;
break;
}
buffer = ensureBufferSize(buffer, pos + 1);
buffer[pos++] = (byte) b;
if (findPattern(buffer, pos, out)) {
break;
}
}
// Pattern has been found (or eof reached).
while (!eof && !isInterrupted() && !shouldStop()) {
// Now just shuffle data from in to out
int n = in.read(buffer);
if (n == -1) {
eof = true;
break;
}
if (n > 0) {
out.write(buffer, 0, n);
out.flush();
}
}
} catch (Throwable t) {
handleException(t);
} finally {
closeStreams();
}
}
protected void closeStreams() {
IOUtils.closeQuietly(out);
IOUtils.closeQuietly(in);
}
protected void handleException(Throwable t) {
t.printStackTrace();
}
protected boolean shouldStop() {
return false;
}
}