package org.jboss.axis.attachments;
import org.jboss.axis.utils.Messages;
import org.jboss.logging.Logger;
import java.io.IOException;
public class DimeDelimitedInputStream extends java.io.FilterInputStream
{
private static Logger log = Logger.getLogger(DimeDelimitedInputStream.class.getName());
java.io.InputStream is = null; volatile boolean closed = true; boolean theEnd = false; boolean moreChunks = false; boolean MB = false; boolean ME = false; DimeTypeNameFormat tnf = null;
String type = null;
String id = null;
long recordLength = 0L; long bytesRead = 0; int dataPadLength = 0; private static byte[] trash = new byte[4];
protected int streamNo = 0;
protected IOException streamInError = null;
protected static int streamCount = 0;
protected static synchronized int newStreamNo()
{
log.debug(Messages.getMessage("streamNo", "" + (streamCount + 1)));
return ++streamCount;
}
static boolean isDebugEnabled = false;
synchronized DimeDelimitedInputStream getNextStream()
throws IOException
{
if (null != streamInError) throw streamInError;
if (theEnd) return null;
if (bytesRead < recordLength || moreChunks) throw new RuntimeException(Messages.getMessage("attach.dimeReadFullyError"));
dataPadLength -= readPad(dataPadLength);
return new DimeDelimitedInputStream(this.is);
}
DimeDelimitedInputStream(java.io.InputStream is) throws IOException
{
super(null); isDebugEnabled = log.isDebugEnabled();
streamNo = newStreamNo();
closed = false;
this.is = is;
readHeader(false);
}
private final int readPad(final int size) throws IOException
{
if (0 == size) return 0;
int read = readFromStream(trash, 0, size);
if (size != read)
{
streamInError = new IOException(Messages.getMessage("attach.dimeNotPaddedCorrectly"));
throw streamInError;
}
return read;
}
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
{
if (length == 0) return 0;
int br = 0;
int brTotal = 0;
do
{
try
{
br = is.read(b, brTotal + start, length - brTotal);
}
catch (IOException e)
{
streamInError = e;
throw e;
}
if (br > 0) brTotal += br;
}
while (br > -1 && brTotal < length);
return br > -1 ? brTotal : br;
}
public String getContentId()
{
return id;
}
public DimeTypeNameFormat getDimeTypeNameFormat()
{
return tnf;
}
public String getType()
{
return type;
}
public synchronized int read(byte[] b, final int off,
final int len) throws IOException
{
if (closed)
{
dataPadLength -= readPad(dataPadLength);
throw new IOException(Messages.getMessage("streamClosed"));
}
return _read(b, off, len);
}
protected int _read(byte[] b, final int off, final int len)
throws IOException
{
if (len < 0)
throw new IllegalArgumentException
(Messages.getMessage("attach.readLengthError",
"" + len));
if (off < 0)
throw new IllegalArgumentException
(Messages.getMessage("attach.readOffsetError",
"" + off));
if (b == null)
throw new IllegalArgumentException
(Messages.getMessage("attach.readArrayNullError"));
if (b.length < off + len)
throw new IllegalArgumentException
(Messages.getMessage("attach.readArraySizeError",
"" + b.length, "" + len, "" + off));
if (null != streamInError) throw streamInError;
if (0 == len) return 0;
if (recordLength == 0 && bytesRead == 0 && !moreChunks)
{
++bytesRead; if (ME)
{
finalClose();
}
return 0;
}
if (bytesRead >= recordLength && !moreChunks)
{
dataPadLength -= readPad(dataPadLength);
if (ME)
{
finalClose();
}
return -1;
}
int totalbytesread = 0;
int bytes2read = 0;
do
{
if (bytesRead >= recordLength && moreChunks)
readHeader(true);
bytes2read = (int)Math.min(recordLength - bytesRead,
(long)len - totalbytesread);
bytes2read = (int)Math.min(recordLength - bytesRead,
(long)len - totalbytesread);
try
{
bytes2read = is.read(b, off + totalbytesread,
bytes2read);
}
catch (IOException e)
{
streamInError = e;
throw e;
}
if (0 < bytes2read)
{
totalbytesread += bytes2read;
bytesRead += bytes2read;
}
}
while (bytes2read > -1 && totalbytesread < len &&
(bytesRead < recordLength || moreChunks));
if (0 > bytes2read)
{
if (moreChunks)
{
streamInError = new IOException(Messages.getMessage("attach.DimeStreamError0"));
throw streamInError;
}
if (bytesRead < recordLength)
{
streamInError = new IOException(Messages.getMessage
("attach.DimeStreamError1",
"" + (recordLength - bytesRead)));
throw streamInError;
}
if (!ME)
{
streamInError = new IOException(Messages.getMessage("attach.DimeStreamError0"));
throw streamInError;
}
dataPadLength = 0;
}
else if (bytesRead >= recordLength)
{
try
{
dataPadLength -= readPad(dataPadLength);
}
catch (IOException e)
{
if (!ME)
throw e;
else
{
dataPadLength = 0;
streamInError = null;
}
}
}
if (bytesRead >= recordLength && ME)
{
finalClose();
}
return totalbytesread >= 0 ? totalbytesread : -1;
}
void readHeader(boolean isChunk) throws IOException
{
bytesRead = 0; if (isChunk)
{
if (!moreChunks)
throw new RuntimeException(Messages.getMessage("attach.DimeStreamError2"));
dataPadLength -= readPad(dataPadLength); }
byte[] header = new byte[12];
if (header.length != readFromStream(header))
{
streamInError = new IOException(Messages.getMessage("attach.DimeStreamError3",
"" + header.length));
throw streamInError;
}
byte version = (byte)((header[0] >>> 3) & 0x1f);
if (version > DimeMultiPart.CURRENT_VERSION)
{
streamInError = new IOException(Messages.getMessage("attach.DimeStreamError4",
"" + version,
"" + DimeMultiPart.CURRENT_VERSION));
throw streamInError;
}
MB = 0 != (0x4 & header[0]);
ME = 0 != (0x2 & header[0]);
moreChunks = 0 != (0x1 & header[0]);
if (!isChunk)
tnf = DimeTypeNameFormat.parseByte((byte)((header[1] >>> 4) & (byte)0xf));
int optionsLength =
((((int)header[2]) << 8) & 0xff00) | ((int)header[3]);
int idLength =
((((int)header[4]) << 8) & 0xff00) | ((int)header[5]);
int typeLength = ((((int)header[6]) << 8) & 0xff00)
| ((int)header[7]);
recordLength = ((((long)header[8]) << 24) & 0xff000000L) |
((((long)header[9]) << 16) & 0xff0000L) |
((((long)header[10]) << 8) & 0xff00L) |
((long)header[11] & 0xffL);
if (0 != optionsLength)
{
byte[] optBytes = new byte[optionsLength];
if (optionsLength != readFromStream(optBytes))
{
streamInError = new IOException(Messages.getMessage("attach.DimeStreamError5",
"" + optionsLength));
throw streamInError;
}
optBytes = null;
int pad = DimeBodyPart.dimePadding(optionsLength);
if (pad != readFromStream(header, 0, pad))
{
streamInError = new IOException(Messages.getMessage("attach.DimeStreamError7"));
throw streamInError;
}
}
if (0 < idLength)
{
byte[] idBytes = new byte[idLength];
if (idLength != readFromStream(idBytes))
{
streamInError = new IOException(Messages.getMessage("attach.DimeStreamError8"));
throw streamInError;
}
if (idLength != 0 && !isChunk)
{
id = new String(idBytes);
}
int pad = DimeBodyPart.dimePadding(idLength);
if (pad != readFromStream(header, 0, pad))
{
streamInError = new IOException(Messages.getMessage("attach.DimeStreamError9"));
throw streamInError;
}
}
if (0 < typeLength)
{
byte[] typeBytes = new byte[typeLength];
if (typeLength != readFromStream(typeBytes))
{
streamInError = new IOException(Messages.getMessage("attach.DimeStreamError10"));
throw streamInError;
}
if (typeLength != 0 && !isChunk)
{
type = new String(typeBytes);
}
int pad = DimeBodyPart.dimePadding(typeLength);
if (pad != readFromStream(header, 0, pad))
{
streamInError = new IOException(Messages.getMessage("attach.DimeStreamError11"));
throw streamInError;
}
}
log.debug("MB:" + MB + ", ME:" + ME + ", CF:" + moreChunks +
"Option length:" + optionsLength +
", ID length:" + idLength +
", typeLength:" + typeLength + ", TYPE_T:" + tnf);
log.debug("id:\"" + id + "\"");
log.debug("type:\"" + type + "\"");
log.debug("recordlength:\"" + recordLength + "\"");
dataPadLength = DimeBodyPart.dimePadding(recordLength);
}
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, 0, 1);
if (read < 0)
return -1;
else
return b[0];
}
public void close() throws IOException
{
synchronized (this)
{
if (closed) return;
closed = true; }
log.debug(Messages.getMessage("bStreamClosed", "" + streamNo));
if (bytesRead < recordLength || moreChunks)
{
byte[] readrest = new byte[1024 * 16];
int bread = 0;
do
{
bread = _read(readrest, 0, readrest.length); }
while (bread > -1);
}
dataPadLength -= readPad(dataPadLength);
}
public void mark(int readlimit)
{ }
public void reset() throws IOException
{
streamInError = new IOException(Messages.getMessage("attach.bounday.mns"));
throw streamInError;
}
public boolean markSupported()
{
return false;
}
public synchronized int available() throws IOException
{
if (null != streamInError) throw streamInError;
int chunkAvail = (int)Math.min((long)
Integer.MAX_VALUE, recordLength - bytesRead);
int streamAvail = 0;
try
{
streamAvail = is.available();
}
catch (IOException e)
{
streamInError = e;
throw e;
}
if (chunkAvail == 0 && moreChunks && (12 + dataPadLength)
<= streamAvail)
{
dataPadLength -= readPad(dataPadLength);
readHeader(true);
return available();
}
return Math.min(streamAvail, chunkAvail);
}
protected void finalClose() throws IOException
{
try
{
theEnd = true;
if (null != is) is.close();
}
finally
{
is = null;
}
}
}