// Copyright 2001-2006, FreeHEP.
package org.freehep.util.io;
import java.io.IOException;
import java.io.InputStream;
/**
* Class to read Tagged blocks from a Stream. The tagged blocks (Tags) contain a
* tagID and a Length, so that known and unknown tags can be read and written
* (using the TaggedOutputStream). The stream also allows to read Actions, which
* again come with a actionCode and a length.
*
* A set of recognized Tags and Actions can be added to this stream. A concrete
* implementation of this stream should decode/read the TagHeader. All Concrete
* tags should be inherited from the Tag class and implement their read methods.
*
* @author Mark Donszelmann
* @author Charles Loomis
* @version $Id: TaggedInputStream.java,v 1.3 2008-05-04 12:22:14 murkle Exp $
*/
public abstract class TaggedInputStream extends ByteCountInputStream {
/**
* Set of tags that can be used by this Stream
*/
protected TagSet tagSet;
/**
* Set of actions that can be used by this Stream
*/
protected ActionSet actionSet;
/**
* Currently read tagHeader, valid during readTag call.
*/
private TagHeader tagHeader;
/**
* Creates a Tagged Input Stream
*
* @param in
* stream to read from
* @param tagSet
* available tag set
* @param actionSet
* available action set
*/
public TaggedInputStream(InputStream in, TagSet tagSet,
ActionSet actionSet) {
this(in, tagSet, actionSet, false);
}
/**
* Creates a Tagged Input Stream
*
* @param in
* stream to read from
* @param tagSet
* available tag set
* @param actionSet
* available action set
* @param littleEndian
* true if stream is little endian
*/
public TaggedInputStream(InputStream in, TagSet tagSet, ActionSet actionSet,
boolean littleEndian) {
super(in, littleEndian, 8);
this.tagSet = tagSet;
this.actionSet = actionSet;
}
/**
* Add tag to tagset
*
* @param tag
* new tag
*/
public void addTag(Tag tag) {
tagSet.addTag(tag);
}
/**
* Decodes and returns the TagHeader, which includes a TagID and a length.
*
* @return Decoded TagHeader
* @throws IOException
* if read fails
*/
protected abstract TagHeader readTagHeader() throws IOException;
/**
* Read a tag.
*
* @return read tag
* @throws IOException
* if read fails
*/
public Tag readTag() throws IOException {
tagHeader = readTagHeader();
if (tagHeader == null) {
return null;
}
int size = (int) tagHeader.getLength();
// Look up the proper tag.
Tag tag = tagSet.get(tagHeader.getTag());
// set max tag length and read tag
pushBuffer(size);
tag = tag.read(tagHeader.getTag(), this, size);
byte[] rest = popBuffer();
// read non-read part of tag
if (rest != null) {
throw new IncompleteTagException(tag, rest);
}
return tag;
}
/**
* Returns the currently valid TagHeader. Can be called durring the
* tag.read() method.
*/
public TagHeader getTagHeader() {
return tagHeader;
}
/**
* Add action to action set.
*
* @param action
* new action
*/
public void addAction(Action action) {
actionSet.addAction(action);
}
/**
* Decodes and returns the ActionHeader, which includes an actionCode and a
* length.
*
* @return decoded ActionHeader
* @throws IOException
* if read fails
*/
protected abstract ActionHeader readActionHeader() throws IOException;
/**
* Reads action.
*
* @return read action
* @throws IOException
* if read fails
*/
public Action readAction() throws IOException {
ActionHeader header = readActionHeader();
if (header == null) {
return null;
}
int size = (int) header.getLength();
// Look up the proper action.
Action action = actionSet.get(header.getAction());
pushBuffer(size);
action = action.read(header.getAction(), this, size);
byte[] rest = popBuffer();
if (rest != null) {
throw new IncompleteActionException(action, rest);
}
return action;
}
}