package org.jboss.axis.attachments;
import org.jboss.axis.utils.Messages;
import org.jboss.logging.Logger;
import java.io.FilterInputStream;
import java.io.IOException;
import java.io.InputStream;
public class BoundaryDelimitedStream extends FilterInputStream
{
private static Logger log = Logger.getLogger(BoundaryDelimitedStream.class.getName());
protected byte[] boundary = null;
int boundaryLen = 0;
int boundaryBufLen = 0;
InputStream is = null;
boolean closed = true;
boolean eos = false;
boolean theEnd = false;
int readbufsz = 0;
byte[] readbuf = null;
int readBufPos = 0;
int readBufEnd = 0;
protected static final int BOUNDARY_NOT_FOUND = Integer.MAX_VALUE;
int boundaryPos = BOUNDARY_NOT_FOUND;
static int streamCount = 0;
protected static synchronized int newStreamNo()
{
log.debug(Messages.getMessage("streamNo", "" + (streamCount + 1)));
return ++streamCount;
}
protected int streamNo = -1;
static boolean isDebugEnabled = false;
public synchronized BoundaryDelimitedStream getNextStream() throws IOException
{
return getNextStream(readbufsz);
}
protected synchronized BoundaryDelimitedStream getNextStream(int readbufsz) throws IOException
{
BoundaryDelimitedStream ret = null;
if (!theEnd)
{
ret = new BoundaryDelimitedStream(this, readbufsz);
}
return ret;
}
protected BoundaryDelimitedStream(BoundaryDelimitedStream prev,
int readbufsz)
throws IOException
{
super(null);
streamNo = newStreamNo();
boundary = prev.boundary;
boundaryLen = prev.boundaryLen;
boundaryBufLen = prev.boundaryBufLen;
skip = prev.skip;
is = prev.is;
closed = false; eos = false; readbufsz = prev.readbufsz;
readbuf = prev.readbuf;
readBufPos = prev.readBufPos + boundaryBufLen;
readBufEnd = prev.readBufEnd;
boundaryPos = boundaryPosition(readbuf, readBufPos, readBufEnd);
prev.theEnd = theEnd; }
BoundaryDelimitedStream(InputStream is, byte[] boundary, int readbufsz)
{
super(null);
isDebugEnabled = log.isDebugEnabled();
streamNo = newStreamNo();
closed = false;
this.is = is;
this.boundary = new byte[boundary.length];
System.arraycopy(boundary, 0, this.boundary, 0, boundary.length);
this.boundaryLen = this.boundary.length;
this.boundaryBufLen = boundaryLen + 2;
this.readbufsz = Math.max((boundaryBufLen) * 2, readbufsz);
}
private final int readFromStream(final byte[] b)
throws IOException
{
return readFromStream(b, 0, b.length);
}
private final int readFromStream(final byte[] b, final int start, final int length)
throws IOException
{
int minRead = Math.max(boundaryBufLen * 2, length);
minRead = Math.min(minRead, length - start);
int br = 0;
int brTotal = 0;
do
{
br = is.read(b, brTotal + start, length - brTotal);
if (br > 0)
{
brTotal += br;
}
}
while ((br > -1) && (brTotal < minRead));
return (brTotal != 0)
? brTotal
: br;
}
public synchronized int read(byte[] b, final int off, final int len)
throws IOException
{
if (closed)
{
throw new IOException(Messages.getMessage("streamClosed"));
}
if (eos)
{
return -1;
}
if (readbuf == null)
{ readbuf = new byte[Math.max(len, readbufsz)];
readBufEnd = readFromStream(readbuf);
if (readBufEnd < 0)
{
readbuf = null;
closed = true;
finalClose();
throw new IOException(Messages.getMessage("eosBeforeMarker"));
}
readBufPos = 0;
boundaryPos = boundaryPosition(readbuf, 0, readBufEnd);
}
int bwritten = 0;
do
{ int bcopy = Math.min(readBufEnd - readBufPos - boundaryBufLen,
len - bwritten);
bcopy = Math.min(bcopy, boundaryPos - readBufPos);
if (bcopy > 0)
{
System.arraycopy(readbuf, readBufPos, b, off + bwritten, bcopy);
bwritten += bcopy;
readBufPos += bcopy;
}
if (readBufPos == boundaryPos)
{
eos = true;
log.debug(Messages.getMessage("atEOS", "" + streamNo));
}
else if (bwritten < len)
{ byte[] dstbuf = readbuf;
if (readbuf.length < len)
{
dstbuf = new byte[len];
}
int movecnt = readBufEnd - readBufPos;
System.arraycopy(readbuf, readBufPos, dstbuf, 0, movecnt);
int readcnt = readFromStream(dstbuf, movecnt,
dstbuf.length - movecnt);
if (readcnt < 0)
{
readbuf = null;
closed = true;
finalClose();
throw new IOException(Messages.getMessage("eosBeforeMarker"));
}
readBufEnd = readcnt + movecnt;
readbuf = dstbuf;
readBufPos = 0;
if (BOUNDARY_NOT_FOUND != boundaryPos)
{
boundaryPos -= movecnt;
}
else
{
boundaryPos = boundaryPosition(readbuf, readBufPos,
readBufEnd); }
}
}
while (!eos && (bwritten < len));
if (log.isDebugEnabled())
{
if (bwritten > 0)
{
byte tb[] = new byte[bwritten];
System.arraycopy(b, off, tb, 0, bwritten);
log.trace(Messages.getMessage("readBStream", new String[]{"" + bwritten, "" + streamNo, new String(tb)}));
}
}
if (eos && theEnd)
{
readbuf = null; }
return bwritten;
}
public int read(byte[] b) throws IOException
{
return read(b, 0, b.length);
}
public int read() throws IOException
{
byte[] b = new byte[1]; int read = read(b);
if (read < 0)
{
return -1;
}
else
{
return b[0] & 0xff;
}
}
public synchronized void close() throws IOException
{
if (closed)
{
return;
}
log.debug(Messages.getMessage("bStreamClosed", "" + streamNo));
closed = true;
if (!eos)
{
byte[] readrest = new byte[1024 * 16];
int bread = 0;
do
{
bread = read(readrest);
}
while (bread > -1);
}
}
public void mark(int readlimit)
{
}
public void reset() throws IOException
{
throw new IOException(Messages.getMessage("attach.bounday.mns"));
}
public boolean markSupported()
{
return false;
}
public int available() throws IOException
{
int bcopy = readBufEnd - readBufPos - boundaryBufLen;
bcopy = Math.min(bcopy, boundaryPos - readBufPos);
return Math.max(0, bcopy);
}
protected int boundaryPosition(byte[] searchbuf, int start, int end) throws IOException
{
int foundAt = boundarySearch(searchbuf, start, end);
if (BOUNDARY_NOT_FOUND != foundAt)
{ if (foundAt + boundaryLen + 2 > end)
{
foundAt = BOUNDARY_NOT_FOUND;
}
else
{
if ((searchbuf[foundAt + boundaryLen] == '-')
&& (searchbuf[foundAt + boundaryLen + 1] == '-'))
{
finalClose();
}
else if ((searchbuf[foundAt + boundaryLen] != 13)
|| (searchbuf[foundAt + boundaryLen + 1] != 10))
{
foundAt = BOUNDARY_NOT_FOUND;
}
}
}
return foundAt;
}
private int[] skip = null;
private int boundarySearch(final byte[] text, final int start,
final int end)
{
int i = 0, j = 0, k = 0;
if (boundaryLen > (end - start))
{
return BOUNDARY_NOT_FOUND;
}
if (null == skip)
{
skip = new int[256];
java.util.Arrays.fill(skip, boundaryLen);
for (k = 0; k < boundaryLen - 1; k++)
{
skip[boundary[k]] = boundaryLen - k - 1;
}
}
for (k = start + boundaryLen - 1; k < end;
k += skip[text[k] & (0xff)])
{
try
{
for (j = boundaryLen - 1, i = k;
(j >= 0) && (text[i] == boundary[j]); j--)
{
i--;
}
}
catch (ArrayIndexOutOfBoundsException e)
{
StringBuffer sb = new StringBuffer();
sb.append(">>>"
+ e); sb.append("start=" + start);
sb.append("k=" + k);
sb.append("text.length=" + text.length);
sb.append("i=" + i);
sb.append("boundary.length=" + boundary.length);
sb.append("j=" + j);
sb.append("end=" + end);
log.warn(Messages.getMessage("exception01", sb.toString()));
throw e;
}
if (j == (-1))
{
return i + 1;
}
}
return BOUNDARY_NOT_FOUND;
}
protected void finalClose() throws IOException
{
if (theEnd) return;
theEnd = true;
is.close();
is = null;
}
public static void printarry(byte[] b, int start, int end)
{
if (log.isDebugEnabled())
{
byte tb[] = new byte[end - start];
System.arraycopy(b, start, tb, 0, end - start);
log.debug("\"" + new String(tb) + "\"");
}
}
}