001    /**
002     *  Licensed to the Apache Software Foundation (ASF) under one or more
003     *  contributor license agreements.  See the NOTICE file distributed with
004     *  this work for additional information regarding copyright ownership.
005     *  The ASF licenses this file to You under the Apache License, Version 2.0
006     *  (the "License"); you may not use this file except in compliance with
007     *  the License.  You may obtain a copy of the License at
008     *
009     *     http://www.apache.org/licenses/LICENSE-2.0
010     *
011     *  Unless required by applicable law or agreed to in writing, software
012     *  distributed under the License is distributed on an "AS IS" BASIS,
013     *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014     *  See the License for the specific language governing permissions and
015     *  limitations under the License.
016     */
017    
018    package org.apache.geronimo.crypto.asn1;
019    
020    import java.io.ByteArrayOutputStream;
021    import java.io.EOFException;
022    import java.io.IOException;
023    import java.io.InputStream;
024    import java.util.Vector;
025    
026    /**
027     * @deprecated use ASN1InputStream
028     */
029    public class BERInputStream
030        extends DERInputStream
031    {
032        private DERObject END_OF_STREAM = new DERObject() {
033                                            void encode(
034                                                DEROutputStream out)
035                                            throws IOException
036                                            {
037                                                throw new IOException("Eeek!");
038                                            }
039                                            public int hashCode()
040                                            {
041                                                return 0;
042                                            }
043                                            public boolean equals(
044                                                Object o)
045                                            {
046                                                return o == this;
047                                            }
048                                        };
049        public BERInputStream(
050            InputStream is)
051        {
052            super(is);
053        }
054    
055        /**
056         * read a string of bytes representing an indefinite length object.
057         */
058        private byte[] readIndefiniteLengthFully()
059            throws IOException
060        {
061            ByteArrayOutputStream   bOut = new ByteArrayOutputStream();
062            int                     b, b1;
063    
064            b1 = read();
065    
066            while ((b = read()) >= 0)
067            {
068                if (b1 == 0 && b == 0)
069                {
070                    break;
071                }
072    
073                bOut.write(b1);
074                b1 = b;
075            }
076    
077            return bOut.toByteArray();
078        }
079    
080        private BERConstructedOctetString buildConstructedOctetString()
081            throws IOException
082        {
083            Vector               octs = new Vector();
084    
085            for (;;)
086            {
087                DERObject        o = readObject();
088    
089                if (o == END_OF_STREAM)
090                {
091                    break;
092                }
093    
094                octs.addElement(o);
095            }
096    
097            return new BERConstructedOctetString(octs);
098        }
099    
100        public DERObject readObject()
101            throws IOException
102        {
103            int tag = read();
104            if (tag == -1)
105            {
106                throw new EOFException();
107            }
108    
109            int     length = readLength();
110    
111            if (length < 0)    // indefinite length method
112            {
113                switch (tag)
114                {
115                case NULL:
116                    return null;
117                case SEQUENCE | CONSTRUCTED:
118                    BERConstructedSequence  seq = new BERConstructedSequence();
119    
120                    for (;;)
121                    {
122                        DERObject   obj = readObject();
123    
124                        if (obj == END_OF_STREAM)
125                        {
126                            break;
127                        }
128    
129                        seq.addObject(obj);
130                    }
131                    return seq;
132                case OCTET_STRING | CONSTRUCTED:
133                    return buildConstructedOctetString();
134                case SET | CONSTRUCTED:
135                    ASN1EncodableVector  v = new ASN1EncodableVector();
136    
137                    for (;;)
138                    {
139                        DERObject   obj = readObject();
140    
141                        if (obj == END_OF_STREAM)
142                        {
143                            break;
144                        }
145    
146                        v.add(obj);
147                    }
148                    return new BERSet(v);
149                default:
150                    //
151                    // with tagged object tag number is bottom 5 bits
152                    //
153                    if ((tag & TAGGED) != 0)
154                    {
155                        if ((tag & 0x1f) == 0x1f)
156                        {
157                            throw new IOException("unsupported high tag encountered");
158                        }
159    
160                        //
161                        // simple type - implicit... return an octet string
162                        //
163                        if ((tag & CONSTRUCTED) == 0)
164                        {
165                            byte[]  bytes = readIndefiniteLengthFully();
166    
167                            return new BERTaggedObject(false, tag & 0x1f, new DEROctetString(bytes));
168                        }
169    
170                        //
171                        // either constructed or explicitly tagged
172                        //
173                        DERObject        dObj = readObject();
174    
175                        if (dObj == END_OF_STREAM)     // empty tag!
176                        {
177                            return new DERTaggedObject(tag & 0x1f);
178                        }
179    
180                        DERObject       next = readObject();
181    
182                        //
183                        // explicitly tagged (probably!) - if it isn't we'd have to
184                        // tell from the context
185                        //
186                        if (next == END_OF_STREAM)
187                        {
188                            return new BERTaggedObject(tag & 0x1f, dObj);
189                        }
190    
191                        //
192                        // another implicit object, we'll create a sequence...
193                        //
194                        seq = new BERConstructedSequence();
195    
196                        seq.addObject(dObj);
197    
198                        do
199                        {
200                            seq.addObject(next);
201                            next = readObject();
202                        }
203                        while (next != END_OF_STREAM);
204    
205                        return new BERTaggedObject(false, tag & 0x1f, seq);
206                    }
207    
208                    throw new IOException("unknown BER object encountered");
209                }
210            }
211            else
212            {
213                if (tag == 0 && length == 0)    // end of contents marker.
214                {
215                    return END_OF_STREAM;
216                }
217    
218                byte[]  bytes = new byte[length];
219    
220                readFully(bytes);
221    
222                return buildObject(tag, bytes);
223            }
224        }
225    }