blob: 43fcad76b6e5a9e60030295d983c5dd8143cf726 [file] [log] [blame]
package org.bouncycastle.asn1;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
public class ASN1StreamParser
{
private final InputStream _in;
private final int _limit;
private static int findLimit(InputStream in)
{
if (in instanceof DefiniteLengthInputStream)
{
return ((DefiniteLengthInputStream)in).getRemaining();
}
return Integer.MAX_VALUE;
}
public ASN1StreamParser(
InputStream in)
{
this(in, findLimit(in));
}
public ASN1StreamParser(
InputStream in,
int limit)
{
this._in = in;
this._limit = limit;
}
public ASN1StreamParser(
byte[] encoding)
{
this(new ByteArrayInputStream(encoding), encoding.length);
}
public DEREncodable readObject()
throws IOException
{
int tag = _in.read();
if (tag == -1)
{
return null;
}
//
// turn of looking for "00" while we resolve the tag
//
set00Check(false);
//
// calculate tag number
//
int tagNo = ASN1InputStream.readTagNumber(_in, tag);
boolean isConstructed = (tag & DERTags.CONSTRUCTED) != 0;
//
// calculate length
//
int length = ASN1InputStream.readLength(_in, _limit);
if (length < 0) // indefinite length method
{
if (!isConstructed)
{
throw new IOException("indefinite length primitive encoding encountered");
}
IndefiniteLengthInputStream indIn = new IndefiniteLengthInputStream(_in);
if ((tag & DERTags.APPLICATION) != 0)
{
ASN1StreamParser sp = new ASN1StreamParser(indIn, _limit);
return new BERApplicationSpecificParser(tagNo, sp);
}
if ((tag & DERTags.TAGGED) != 0)
{
return new BERTaggedObjectParser(tag, tagNo, indIn);
}
ASN1StreamParser sp = new ASN1StreamParser(indIn, _limit);
// TODO There are other tags that may be constructed (e.g. BIT_STRING)
switch (tagNo)
{
case DERTags.OCTET_STRING:
return new BEROctetStringParser(sp);
case DERTags.SEQUENCE:
return new BERSequenceParser(sp);
case DERTags.SET:
return new BERSetParser(sp);
case DERTags.EXTERNAL:{
return new DERExternalParser(sp);
}
default:
throw new IOException("unknown BER object encountered: 0x" + Integer.toHexString(tagNo));
}
}
else
{
DefiniteLengthInputStream defIn = new DefiniteLengthInputStream(_in, length);
if ((tag & DERTags.APPLICATION) != 0)
{
return new DERApplicationSpecific(isConstructed, tagNo, defIn.toByteArray());
}
if ((tag & DERTags.TAGGED) != 0)
{
return new BERTaggedObjectParser(tag, tagNo, defIn);
}
if (isConstructed)
{
// TODO There are other tags that may be constructed (e.g. BIT_STRING)
switch (tagNo)
{
case DERTags.OCTET_STRING:
//
// yes, people actually do this...
//
return new BEROctetStringParser(new ASN1StreamParser(defIn));
case DERTags.SEQUENCE:
return new DERSequenceParser(new ASN1StreamParser(defIn));
case DERTags.SET:
return new DERSetParser(new ASN1StreamParser(defIn));
case DERTags.EXTERNAL:
return new DERExternalParser(new ASN1StreamParser(defIn));
default:
// TODO Add DERUnknownTagParser class?
return new DERUnknownTag(true, tagNo, defIn.toByteArray());
}
}
// Some primitive encodings can be handled by parsers too...
switch (tagNo)
{
case DERTags.OCTET_STRING:
return new DEROctetStringParser(defIn);
}
return ASN1InputStream.createPrimitiveDERObject(tagNo, defIn.toByteArray());
}
}
private void set00Check(boolean enabled)
{
if (_in instanceof IndefiniteLengthInputStream)
{
((IndefiniteLengthInputStream)_in).setEofOn00(enabled);
}
}
ASN1EncodableVector readVector() throws IOException
{
ASN1EncodableVector v = new ASN1EncodableVector();
DEREncodable obj;
while ((obj = readObject()) != null)
{
v.add(obj.getDERObject());
}
return v;
}
}