package org.ws4d.java.security;
import java.io.IOException;
import java.io.InputStream;
import org.ws4d.java.structures.ArrayList;
import org.ws4d.java.structures.Iterator;
import org.ws4d.java.structures.List;
/**
* This class wraps an InputStream and, after the XML document has been read, is
* able to deliver the parts of the document that have been referenced by ID in
* the security part of the soap header.
*/
public class IDawareInputStream extends InputStream {
private InputStream wrappedStream;
private ArrayList bufAList = new ArrayList();
private String[] ids;
private ArrayList idArrayList = null;
private ArrayList[] parts;
private int currentPart = -1;
private int currStart = -1;
private int currEnd = -1;
private char[] ferengis = { '<', '/', 'I', 'D', '=', '"', ' ', '\\', '>' };
private char[] romulans = { 'R', 'e', 'f', 's', '=', '"' };
private int romulanCounter = -1;
private String waitingForEndofPart = null;
private String buf = null;
private int idFinder = -1;
private int lastStart = -1;
private boolean isAttribute = false;
private boolean idDetectionDone = false;
/**
* @param is the InputStream from witch to read.
* @param ids the IDs (if known) of the signed message parts. If not known
* null.
*/
public IDawareInputStream(InputStream is, String[] ids) {
wrappedStream = is;
this.ids = ids;
currentPart = -1;
currStart = -1;
currEnd = -1;
romulanCounter = -1;
idFinder = -1;
lastStart = -1;
parts = ids == null ? null : new ArrayList[ids.length];
if (parts != null) idDetectionDone = true;
}
private void setIDs(ArrayList ids) {
Iterator it = ids.iterator();
this.ids = new String[ids.size()];
for (int i = 0; it.hasNext(); i++) {
this.ids[i] = (String) it.next();
}
parts = new ArrayList[ids.size()];
}
/**
* @return the name of the current element
*/
private String getCurrentElmentsName() {
String element = new String();
for (int i = lastStart + 1; true; i++) {
if ((((Integer) bufAList.get(i)).intValue() == ferengis[6] || ((Integer) bufAList.get(i)).intValue() == ferengis[8]) && element != "") {
return element;
} else
element += (char) ((Integer) bufAList.get(i)).intValue();
}
}
/**
* @return the latest position of a startTag element.
*/
private int getLastStartTagPos() {
return bufAList.lastIndexOf(new Integer(ferengis[0]));
}
/*
* (non-Javadoc)
* @see java.io.InputStream#read()
*/
public int read() throws IOException {
// discover the referenced parts in the XML documents. If not supplied
// discover the "Refs:" section as well. Yes, thats a little bit more
// work.
int b = wrappedStream.read();
if (b == ferengis[0]) lastStart = bufAList.size();
if (bufAList.size() > 0 && b != ferengis[1] && ((Integer) bufAList.get(bufAList.size() - 1)).intValue() == ferengis[0]) {
isAttribute = true;
idFinder = -1;
} else if (waitingForEndofPart == null && isAttribute == true && b == ferengis[2] && ((Integer) bufAList.get(bufAList.size() - 1)).intValue() == ferengis[6]) {
idFinder = 0;
buf = new String();
} else if (!idDetectionDone && idArrayList != null) {
if (b == ferengis[6]) {
idArrayList.add(new String());
} else if (b == ferengis[5] && (char) ((Integer) bufAList.get(bufAList.size() - 1)).intValue() != ferengis[1]) {
this.setIDs(idArrayList);
idArrayList = null;
idDetectionDone = true;
} else
idArrayList.set(idArrayList.size() - 1, ((String) idArrayList.get(idArrayList.size() - 1)).concat("" + (char) b));
} else if (idFinder != -1 && idFinder <= 2 && b == ferengis[3 + idFinder]) {
idFinder++;
} else if (idFinder >= 2 && !(b == ferengis[5] && ((Integer) bufAList.get(bufAList.size() - 1)).intValue() != ferengis[7])) {
buf += ((char) b);
} else if (idFinder >= 2) {
idFinder = -1;
// is it one of the relevant IDs?
for (int y = 0; ids != null && y < ids.length; y++) {
if (ids[y].equals(buf)) {
waitingForEndofPart = getCurrentElmentsName();
parts[y] = new ArrayList();
currentPart = y;
currStart = getLastStartTagPos();
}
}
} else if (currEnd <= -1 && currentPart > -1 && b == ferengis[1] && ((Integer) bufAList.get(bufAList.size() - 1)).intValue() == ferengis[0]) {
currEnd = 0;
} else if (currentPart > -1 && currEnd > -1 && waitingForEndofPart.length() - 1 < currEnd && ((Integer) bufAList.get(bufAList.size() - 1)).intValue() == ferengis[8]) {
int i = bufAList.size();
List l = bufAList.subList(currStart, i);
parts[currentPart] = new ArrayList(l);
// contain the ghosts i called
currentPart = -1;
currEnd = -1;
currStart = -1;
waitingForEndofPart = null;
} else if (currEnd > -1 && ((waitingForEndofPart == null && currentPart > -1) || ((currentPart > -1 && waitingForEndofPart != null) && (!(currEnd > waitingForEndofPart.length() - 1) && b != waitingForEndofPart.charAt(currEnd)))))
currEnd = -1;
else if (currentPart > -1 && currEnd > -1) {
currEnd++;
} else if (waitingForEndofPart == null && !idDetectionDone && isAttribute && ids == null) {
romulanCounter++;
if (romulanCounter + 1 >= romulans.length) {
idArrayList = new ArrayList();
idArrayList.add(new String());
} else if (romulans[romulanCounter] != b) {
romulanCounter = -1;
}
}
bufAList.add(new Integer(b));
return b;
}
/**
* @return the byte arrays of the referred message parts. In the same order
* as given as input.
*/
public byte[][] getPartsByteArrays() {
if (parts == null) return null;
byte[][] reVal = new byte[parts.length][];
for (int i = 0; i < parts.length; i++) {
if (parts[i] == null) return null;
reVal[i] = new byte[parts[i].size()];
for (int y = 0; y < parts[i].size(); y++) {
reVal[i][y] = (byte) ((Integer) parts[i].get(y)).intValue();
}
}
return reVal;
}
/**
* returns the id referenced in the security part of the header
*
* @return
*/
public String[] getIds() {
return ids;
}
}