| package org.bouncycastle.asn1; |
| |
| import java.io.ByteArrayOutputStream; |
| import java.io.EOFException; |
| import java.io.IOException; |
| import java.io.InputStream; |
| import java.util.Vector; |
| |
| /** |
| * @deprecated use ASN1InputStream |
| */ |
| public class BERInputStream |
| extends DERInputStream |
| { |
| private static final DERObject END_OF_STREAM = new DERObject() |
| { |
| void encode( |
| DEROutputStream out) |
| throws IOException |
| { |
| throw new IOException("Eeek!"); |
| } |
| public int hashCode() |
| { |
| return 0; |
| } |
| public boolean equals( |
| Object o) |
| { |
| return o == this; |
| } |
| }; |
| public BERInputStream( |
| InputStream is) |
| { |
| super(is); |
| } |
| |
| /** |
| * read a string of bytes representing an indefinite length object. |
| */ |
| private byte[] readIndefiniteLengthFully() |
| throws IOException |
| { |
| ByteArrayOutputStream bOut = new ByteArrayOutputStream(); |
| int b, b1; |
| |
| b1 = read(); |
| |
| while ((b = read()) >= 0) |
| { |
| if (b1 == 0 && b == 0) |
| { |
| break; |
| } |
| |
| bOut.write(b1); |
| b1 = b; |
| } |
| |
| return bOut.toByteArray(); |
| } |
| |
| private BERConstructedOctetString buildConstructedOctetString() |
| throws IOException |
| { |
| Vector octs = new Vector(); |
| |
| for (;;) |
| { |
| DERObject o = readObject(); |
| |
| if (o == END_OF_STREAM) |
| { |
| break; |
| } |
| |
| octs.addElement(o); |
| } |
| |
| return new BERConstructedOctetString(octs); |
| } |
| |
| public DERObject readObject() |
| throws IOException |
| { |
| int tag = read(); |
| if (tag == -1) |
| { |
| throw new EOFException(); |
| } |
| |
| int length = readLength(); |
| |
| if (length < 0) // indefinite length method |
| { |
| switch (tag) |
| { |
| case NULL: |
| return null; |
| case SEQUENCE | CONSTRUCTED: |
| BERConstructedSequence seq = new BERConstructedSequence(); |
| |
| for (;;) |
| { |
| DERObject obj = readObject(); |
| |
| if (obj == END_OF_STREAM) |
| { |
| break; |
| } |
| |
| seq.addObject(obj); |
| } |
| return seq; |
| case OCTET_STRING | CONSTRUCTED: |
| return buildConstructedOctetString(); |
| case SET | CONSTRUCTED: |
| ASN1EncodableVector v = new ASN1EncodableVector(); |
| |
| for (;;) |
| { |
| DERObject obj = readObject(); |
| |
| if (obj == END_OF_STREAM) |
| { |
| break; |
| } |
| |
| v.add(obj); |
| } |
| return new BERSet(v); |
| default: |
| // |
| // with tagged object tag number is bottom 5 bits |
| // |
| if ((tag & TAGGED) != 0) |
| { |
| if ((tag & 0x1f) == 0x1f) |
| { |
| throw new IOException("unsupported high tag encountered"); |
| } |
| |
| // |
| // simple type - implicit... return an octet string |
| // |
| if ((tag & CONSTRUCTED) == 0) |
| { |
| byte[] bytes = readIndefiniteLengthFully(); |
| |
| return new BERTaggedObject(false, tag & 0x1f, new DEROctetString(bytes)); |
| } |
| |
| // |
| // either constructed or explicitly tagged |
| // |
| DERObject dObj = readObject(); |
| |
| if (dObj == END_OF_STREAM) // empty tag! |
| { |
| return new DERTaggedObject(tag & 0x1f); |
| } |
| |
| DERObject next = readObject(); |
| |
| // |
| // explicitly tagged (probably!) - if it isn't we'd have to |
| // tell from the context |
| // |
| if (next == END_OF_STREAM) |
| { |
| return new BERTaggedObject(tag & 0x1f, dObj); |
| } |
| |
| // |
| // another implicit object, we'll create a sequence... |
| // |
| seq = new BERConstructedSequence(); |
| |
| seq.addObject(dObj); |
| |
| do |
| { |
| seq.addObject(next); |
| next = readObject(); |
| } |
| while (next != END_OF_STREAM); |
| |
| return new BERTaggedObject(false, tag & 0x1f, seq); |
| } |
| |
| throw new IOException("unknown BER object encountered"); |
| } |
| } |
| else |
| { |
| if (tag == 0 && length == 0) // end of contents marker. |
| { |
| return END_OF_STREAM; |
| } |
| |
| byte[] bytes = new byte[length]; |
| |
| readFully(bytes); |
| |
| return buildObject(tag, bytes); |
| } |
| } |
| } |