001    /*
002     * Copyright 2009-2013 UnboundID Corp.
003     * All Rights Reserved.
004     */
005    /*
006     * Copyright (C) 2009-2013 UnboundID Corp.
007     *
008     * This program is free software; you can redistribute it and/or modify
009     * it under the terms of the GNU General Public License (GPLv2 only)
010     * or the terms of the GNU Lesser General Public License (LGPLv2.1 only)
011     * as published by the Free Software Foundation.
012     *
013     * This program is distributed in the hope that it will be useful,
014     * but WITHOUT ANY WARRANTY; without even the implied warranty of
015     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
016     * GNU General Public License for more details.
017     *
018     * You should have received a copy of the GNU General Public License
019     * along with this program; if not, see <http://www.gnu.org/licenses>.
020     */
021    package com.unboundid.asn1;
022    
023    
024    
025    import java.io.BufferedInputStream;
026    import java.io.InputStream;
027    import java.io.IOException;
028    import java.net.SocketTimeoutException;
029    import java.util.logging.Level;
030    
031    import com.unboundid.util.Mutable;
032    import com.unboundid.util.ThreadSafety;
033    import com.unboundid.util.ThreadSafetyLevel;
034    
035    import static com.unboundid.asn1.ASN1Messages.*;
036    import static com.unboundid.util.Debug.*;
037    import static com.unboundid.util.StaticUtils.*;
038    
039    
040    
041    /**
042     * This class provides a mechanism for ASN.1 elements (including sequences and
043     * sets) from an input stream in a manner that allows the data to be decoded on
044     * the fly without constructing {@link ASN1Element} objects if they are not
045     * needed.  If any method in this class throws an {@code IOException}, then the
046     * caller must close this reader and must not attempt to use it any more.
047     * {@code ASN1StreamReader} instances are not threadsafe and must not be
048     * accessed concurrently by multiple threads.
049     */
050    @Mutable()
051    @ThreadSafety(level=ThreadSafetyLevel.NOT_THREADSAFE)
052    public final class ASN1StreamReader
053    {
054      // Indicates whether socket timeout exceptions should be ignored for the
055      // initial read of an element.
056      private boolean ignoreInitialSocketTimeout;
057    
058      // Indicates whether socket timeout exceptions should be ignored for
059      // subsequent reads of an element.
060      private boolean ignoreSubsequentSocketTimeout;
061    
062      // The input stream from which data will be read.
063      private final InputStream inputStream;
064    
065      // The maximum element size that will be allowed.
066      private final int maxElementSize;
067    
068      // The total number of bytes read from the underlying input stream.
069      private long totalBytesRead;
070    
071    
072    
073      /**
074       * Creates a new ASN.1 stream reader that will read data from the provided
075       * input stream.  It will use a maximum element size of
076       * {@code Integer.MAX_VALUE}.
077       *
078       * @param  inputStream  The input stream from which data should be read.  If
079       *                      the provided input stream does not support the use of
080       *                      the {@code mark} and {@code reset} methods, then it
081       *                      will be wrapped with a {@code BufferedInputStream}.
082       */
083      public ASN1StreamReader(final InputStream inputStream)
084      {
085        this(inputStream, Integer.MAX_VALUE);
086      }
087    
088    
089    
090      /**
091       * Creates a new ASN.1 stream reader that will read data from the provided
092       * input stream.  It will use a maximum element size of
093       * {@code Integer.MAX_VALUE}.
094       *
095       * @param  inputStream     The input stream from which data should be read.
096       *                         If the provided input stream does not support the
097       *                         use of the {@code mark} and {@code reset} methods,
098       *                         then it will be wrapped with a
099       *                         {@code BufferedInputStream}.
100       * @param  maxElementSize  The maximum size in bytes of an ASN.1 element that
101       *                         may be read.  A value less than or equal to zero
102       *                         will be interpreted as {@code Integer.MAX_VALUE}.
103       */
104      public ASN1StreamReader(final InputStream inputStream,
105                              final int maxElementSize)
106      {
107        if (inputStream.markSupported())
108        {
109          this.inputStream = inputStream;
110        }
111        else
112        {
113          this.inputStream = new BufferedInputStream(inputStream);
114        }
115    
116        if (maxElementSize > 0)
117        {
118          this.maxElementSize = maxElementSize;
119        }
120        else
121        {
122          this.maxElementSize = Integer.MAX_VALUE;
123        }
124    
125        totalBytesRead                = 0L;
126        ignoreInitialSocketTimeout    = false;
127        ignoreSubsequentSocketTimeout = false;
128      }
129    
130    
131    
132      /**
133       * Closes this ASN.1 stream reader and the underlying input stream.  This
134       * reader must not be used after it has been closed.
135       *
136       * @throws  IOException  If a problem occurs while closing the underlying
137       *                       input stream.
138       */
139      public void close()
140             throws IOException
141      {
142        inputStream.close();
143      }
144    
145    
146    
147      /**
148       * Retrieves the total number of bytes read so far from the underlying input
149       * stream.
150       *
151       * @return  The total number of bytes read so far from the underlying input
152       *          stream.
153       */
154      long getTotalBytesRead()
155      {
156        return totalBytesRead;
157      }
158    
159    
160    
161      /**
162       * Indicates whether to ignore {@code java.net.SocketTimeoutException}
163       * exceptions that may be caught during processing.
164       *
165       * @return  {@code true} if {@code SocketTimeoutException} exceptions should
166       *          be ignored, or {@code false} if they should not be ignored and
167       *          should be propagated to the caller.
168       *
169       * @deprecated  Use the {@link #ignoreInitialSocketTimeoutException()} and
170       *              {@link #ignoreSubsequentSocketTimeoutException()} methods
171       *              instead.
172       */
173      @Deprecated()
174      public boolean ignoreSocketTimeoutException()
175      {
176        return ignoreInitialSocketTimeout;
177      }
178    
179    
180    
181      /**
182       * Indicates whether to ignore {@code java.net.SocketTimeoutException}
183       * exceptions that may be caught while trying to read the first byte of an
184       * element.
185       *
186       * @return  {@code true} if {@code SocketTimeoutException} exceptions should
187       *          be ignored while trying to read the first byte of an element, or
188       *          {@code false} if they should not be ignored and should be
189       *          propagated to the caller.
190       */
191      public boolean ignoreInitialSocketTimeoutException()
192      {
193        return ignoreInitialSocketTimeout;
194      }
195    
196    
197    
198      /**
199       * Indicates whether to ignore {@code java.net.SocketTimeoutException}
200       * exceptions that may be caught while trying to read subsequent bytes of an
201       * element (after one or more bytes have already been read for that element).
202       *
203       * @return  {@code true} if {@code SocketTimeoutException} exceptions should
204       *          be ignored while trying to read subsequent bytes of an element, or
205       *          {@code false} if they should not be ignored and should be
206       *          propagated to the caller.
207       */
208      public boolean ignoreSubsequentSocketTimeoutException()
209      {
210        return ignoreSubsequentSocketTimeout;
211      }
212    
213    
214    
215      /**
216       * Indicates whether to ignore {@code java.net.SocketTimeoutException}
217       * exceptions that may be caught during processing.
218       *
219       * @param  ignoreSocketTimeout  Indicates whether to ignore
220       *                              {@code SocketTimeoutException} exceptions that
221       *                              may be caught during processing.
222       *
223       * @deprecated  Use the {@link #setIgnoreSocketTimeout(boolean,boolean)}
224       *              method instead.
225       */
226      @Deprecated()
227      public void setIgnoreSocketTimeout(final boolean ignoreSocketTimeout)
228      {
229        ignoreInitialSocketTimeout    = ignoreSocketTimeout;
230        ignoreSubsequentSocketTimeout = ignoreSocketTimeout;
231      }
232    
233    
234    
235      /**
236       * Indicates whether to ignore {@code java.net.SocketTimeoutException}
237       * exceptions that may be caught during processing.
238       *
239       * @param  ignoreInitialSocketTimeout     Indicates whether to ignore
240       *                                        {@code SocketTimeoutException}
241       *                                        exceptions that may be caught while
242       *                                        trying to read the first byte of an
243       *                                        element.
244       * @param  ignoreSubsequentSocketTimeout  Indicates whether to ignore
245       *                                        {@code SocketTimeoutException}
246       *                                        exceptions that may be caught while
247       *                                        reading beyond the first byte of an
248       *                                        element.
249       */
250      public void setIgnoreSocketTimeout(final boolean ignoreInitialSocketTimeout,
251                       final boolean ignoreSubsequentSocketTimeout)
252      {
253        this.ignoreInitialSocketTimeout    = ignoreInitialSocketTimeout;
254        this.ignoreSubsequentSocketTimeout = ignoreSubsequentSocketTimeout;
255      }
256    
257    
258    
259      /**
260       * Peeks at the next byte to be read from the input stream without actually
261       * consuming it.
262       *
263       * @return  An integer value encapsulating the BER type of the next element in
264       *          the input stream, or -1 if the end of the input stream has been
265       *          reached and there is no data to be read.  If a value of -1 is
266       *          returned, then the input stream will not have been closed since
267       *          this method is not intended to have any impact on the underlying
268       *          input stream.
269       *
270       * @throws  IOException  If a problem occurs while reading from the input
271       *                       stream.
272       */
273      public int peek()
274             throws IOException
275      {
276        inputStream.mark(1);
277        final int byteRead = read(true);
278        inputStream.reset();
279    
280        return byteRead;
281      }
282    
283    
284    
285      /**
286       * Reads the BER type of the next element from the input stream.  This may not
287       * be called if a previous element has been started but not yet completed.
288       *
289       * @return  An integer value encapsulating the BER type of the next element in
290       *          the input stream, or -1 if the end of the input stream has been
291       *          reached and there is no data to be read.  If a value of -1 is
292       *          returned, then the input stream will have been closed.
293       *
294       * @throws  IOException  If a problem occurs while reading from the input
295       *                       stream.
296       */
297      private int readType()
298              throws IOException
299      {
300        final int typeInt = read(true);
301        if (typeInt < 0)
302        {
303          close();
304        }
305        else
306        {
307          totalBytesRead++;
308        }
309        return typeInt;
310      }
311    
312    
313    
314      /**
315       * Reads the length of the next element from the input stream.  This may only
316       * be called after reading the BER type.
317       *
318       * @return  The length of the next element from the input stream.
319       *
320       * @throws  IOException  If a problem occurs while reading from the input
321       *                       stream, if the end of the stream has been reached, or
322       *                       if the decoded length is greater than the maximum
323       *                       allowed length.
324       */
325      private int readLength()
326              throws IOException
327      {
328        int length = read(false);
329        if (length < 0)
330        {
331          throw new IOException(ERR_READ_END_BEFORE_FIRST_LENGTH.get());
332        }
333    
334        totalBytesRead++;
335        if (length > 127)
336        {
337          final int numLengthBytes = length & 0x7F;
338          length = 0;
339          if ((numLengthBytes < 1) || (numLengthBytes > 4))
340          {
341            throw new IOException(ERR_READ_LENGTH_TOO_LONG.get(numLengthBytes));
342          }
343    
344          for (int i=0; i < numLengthBytes; i++)
345          {
346            final int lengthInt = read(false);
347            if (lengthInt < 0)
348            {
349              throw new IOException(ERR_READ_END_BEFORE_LENGTH_END.get());
350            }
351    
352            length <<= 8;
353            length |= (lengthInt & 0xFF);
354          }
355    
356          totalBytesRead += numLengthBytes;
357        }
358    
359        if ((length < 0) || ((maxElementSize > 0) && (length > maxElementSize)))
360        {
361          throw new IOException(ERR_READ_LENGTH_EXCEEDS_MAX.get(length,
362                                                                maxElementSize));
363        }
364    
365        return length;
366      }
367    
368    
369    
370      /**
371       * Skips over the specified number of bytes.
372       *
373       * @param  numBytes  The number of bytes to skip.
374       *
375       * @throws  IOException  If a problem occurs while reading from the input
376       *                       stream, or if the end of the stream is reached before
377       *                       having skipped the specified number of bytes.
378       */
379      private void skip(final int numBytes)
380              throws IOException
381      {
382        if (numBytes <= 0)
383        {
384          return;
385        }
386    
387        long totalBytesSkipped = inputStream.skip(numBytes);
388        while (totalBytesSkipped < numBytes)
389        {
390          final long bytesSkipped = inputStream.skip(numBytes - totalBytesSkipped);
391          if (bytesSkipped <= 0)
392          {
393            while (totalBytesSkipped < numBytes)
394            {
395              final int byteRead = read(false);
396              if (byteRead < 0)
397              {
398                throw new IOException(ERR_READ_END_BEFORE_VALUE_END.get());
399              }
400              totalBytesSkipped++;
401            }
402          }
403          else
404          {
405            totalBytesSkipped += bytesSkipped;
406          }
407        }
408    
409        totalBytesRead += numBytes;
410      }
411    
412    
413    
414      /**
415       * Reads a complete ASN.1 element from the input stream.
416       *
417       * @return  The ASN.1 element read from the input stream, or {@code null} if
418       *          the end of the input stream was reached before any data could be
419       *          read.  If {@code null} is returned, then the input stream will
420       *          have been closed.
421       *
422       * @throws  IOException  If a problem occurs while reading from the input
423       *                       stream, if the end of the input stream is reached in
424       *                       the middle of the element, or or if an attempt is
425       *                       made to read an element larger than the maximum
426       *                       allowed size.
427       */
428      public ASN1Element readElement()
429             throws IOException
430      {
431        final int type = readType();
432        if (type < 0)
433        {
434          return null;
435        }
436    
437        final int length = readLength();
438    
439        int valueBytesRead = 0;
440        int bytesRemaining = length;
441        final byte[] value = new byte[length];
442        while (valueBytesRead < length)
443        {
444          final int bytesRead = read(false, value, valueBytesRead, bytesRemaining);
445          if (bytesRead < 0)
446          {
447            throw new IOException(ERR_READ_END_BEFORE_VALUE_END.get());
448          }
449    
450          valueBytesRead += bytesRead;
451          bytesRemaining -= bytesRead;
452        }
453    
454        totalBytesRead += length;
455        final ASN1Element e = new ASN1Element((byte) type, value);
456        debugASN1Read(e);
457        return e;
458      }
459    
460    
461    
462      /**
463       * Reads an ASN.1 Boolean element from the input stream and returns the value
464       * as a {@code Boolean}.
465       *
466       * @return  The {@code Boolean} value of the ASN.1 Boolean element read, or
467       *          {@code null} if the end of the input stream was reached before any
468       *          data could be read.  If {@code null} is returned, then the input
469       *          stream will have been closed.
470       *
471       * @throws  IOException  If a problem occurs while reading from the input
472       *                       stream, if the end of the input stream is reached in
473       *                       the middle of the element, or or if an attempt is
474       *                       made to read an element larger than the maximum
475       *                       allowed size.
476       *
477       * @throws  ASN1Exception  If the data read cannot be parsed as an ASN.1
478       *                         Boolean element.
479       */
480      public Boolean readBoolean()
481             throws IOException, ASN1Exception
482      {
483        final int type = readType();
484        if (type < 0)
485        {
486          return null;
487        }
488    
489        final int length = readLength();
490    
491        if (length == 1)
492        {
493          final int value = read(false);
494          if (value < 0)
495          {
496            throw new IOException(ERR_READ_END_BEFORE_VALUE_END.get());
497          }
498    
499          totalBytesRead++;
500          return (value != 0);
501        }
502        else
503        {
504          skip(length);
505          throw new ASN1Exception(ERR_BOOLEAN_INVALID_LENGTH.get());
506        }
507      }
508    
509    
510    
511      /**
512       * Reads an ASN.1 enumerated element from the input stream and returns the
513       * value as an {@code Integer}.
514       *
515       * @return  The {@code Integer} value of the ASN.1 enumerated element read, or
516       *          {@code null} if the end of the input stream was reached before any
517       *          data could be read.  If {@code null} is returned, then the input
518       *          stream will have been closed.
519       *
520       * @throws  IOException  If a problem occurs while reading from the input
521       *                       stream, if the end of the input stream is reached in
522       *                       the middle of the element, or or if an attempt is
523       *                       made to read an element larger than the maximum
524       *                       allowed size.
525       *
526       * @throws  ASN1Exception  If the data read cannot be parsed as an ASN.1
527       *                         enumerated element.
528       */
529      public Integer readEnumerated()
530             throws IOException, ASN1Exception
531      {
532        return readInteger();
533      }
534    
535    
536    
537      /**
538       * Reads an ASN.1 integer element from the input stream and returns the value
539       * as an {@code Integer}.
540       *
541       * @return  The {@code Integer} value of the ASN.1 integer element read, or
542       *          {@code null} if the end of the input stream was reached before any
543       *          data could be read.  If {@code null} is returned, then the input
544       *          stream will have been closed.
545       *
546       * @throws  IOException  If a problem occurs while reading from the input
547       *                       stream, if the end of the input stream is reached in
548       *                       the middle of the element, or or if an attempt is
549       *                       made to read an element larger than the maximum
550       *                       allowed size.
551       *
552       * @throws  ASN1Exception  If the data read cannot be parsed as an ASN.1
553       *                         integer element.
554       */
555      public Integer readInteger()
556             throws IOException, ASN1Exception
557      {
558        final int type = readType();
559        if (type < 0)
560        {
561          return null;
562        }
563    
564        final int length = readLength();
565        if ((length == 0) || (length > 4))
566        {
567          skip(length);
568          throw new ASN1Exception(ERR_INTEGER_INVALID_LENGTH.get(length));
569        }
570    
571        boolean negative = false;
572        int intValue = 0;
573        for (int i=0; i < length; i++)
574        {
575          final int byteRead = read(false);
576          if (byteRead < 0)
577          {
578            throw new IOException(ERR_READ_END_BEFORE_VALUE_END.get());
579          }
580    
581          if (i == 0)
582          {
583            negative = ((byteRead & 0x80) != 0x00);
584          }
585    
586          intValue <<= 8;
587          intValue |= (byteRead & 0xFF);
588        }
589    
590        if (negative)
591        {
592          switch (length)
593          {
594            case 1:
595              intValue |= 0xFFFFFF00;
596              break;
597            case 2:
598              intValue |= 0xFFFF0000;
599              break;
600            case 3:
601              intValue |= 0xFF000000;
602              break;
603          }
604        }
605    
606        totalBytesRead += length;
607        return intValue;
608      }
609    
610    
611    
612      /**
613       * Reads an ASN.1 integer element from the input stream and returns the value
614       * as a {@code Long}.
615       *
616       * @return  The {@code Long} value of the ASN.1 integer element read, or
617       *          {@code null} if the end of the input stream was reached before any
618       *          data could be read.  If {@code null} is returned, then the input
619       *          stream will have been closed.
620       *
621       * @throws  IOException  If a problem occurs while reading from the input
622       *                       stream, if the end of the input stream is reached in
623       *                       the middle of the element, or or if an attempt is
624       *                       made to read an element larger than the maximum
625       *                       allowed size.
626       *
627       * @throws  ASN1Exception  If the data read cannot be parsed as an ASN.1
628       *                         integer element.
629       */
630      public Long readLong()
631             throws IOException, ASN1Exception
632      {
633        final int type = readType();
634        if (type < 0)
635        {
636          return null;
637        }
638    
639        final int length = readLength();
640        if ((length == 0) || (length > 8))
641        {
642          skip(length);
643          throw new ASN1Exception(ERR_LONG_INVALID_LENGTH.get(length));
644        }
645    
646        boolean negative = false;
647        long longValue = 0;
648        for (int i=0; i < length; i++)
649        {
650          final int byteRead = read(false);
651          if (byteRead < 0)
652          {
653            throw new IOException(ERR_READ_END_BEFORE_VALUE_END.get());
654          }
655    
656          if (i == 0)
657          {
658            negative = ((byteRead & 0x80) != 0x00);
659          }
660    
661          longValue <<= 8;
662          longValue |= (byteRead & 0xFFL);
663        }
664    
665        if (negative)
666        {
667          switch (length)
668          {
669            case 1:
670              longValue |= 0xFFFFFFFFFFFFFF00L;
671              break;
672            case 2:
673              longValue |= 0xFFFFFFFFFFFF0000L;
674              break;
675            case 3:
676              longValue |= 0xFFFFFFFFFF000000L;
677              break;
678            case 4:
679              longValue |= 0xFFFFFFFF00000000L;
680              break;
681            case 5:
682              longValue |= 0xFFFFFF0000000000L;
683              break;
684            case 6:
685              longValue |= 0xFFFF000000000000L;
686              break;
687            case 7:
688              longValue |= 0xFF00000000000000L;
689              break;
690          }
691        }
692    
693        totalBytesRead += length;
694        return longValue;
695      }
696    
697    
698    
699      /**
700       * Reads an ASN.1 null element from the input stream.  No value will be
701       * returned but the null element will be consumed.
702       *
703       * @throws  IOException  If a problem occurs while reading from the input
704       *                       stream, if the end of the input stream is reached in
705       *                       the middle of the element, or or if an attempt is
706       *                       made to read an element larger than the maximum
707       *                       allowed size.
708       *
709       * @throws  ASN1Exception  If the data read cannot be parsed as an ASN.1 null
710       *                         element.
711       */
712      public void readNull()
713             throws IOException, ASN1Exception
714      {
715        final int type = readType();
716        if (type < 0)
717        {
718          return;
719        }
720    
721        final int length = readLength();
722    
723        if (length != 0)
724        {
725          skip(length);
726          throw new ASN1Exception(ERR_NULL_HAS_VALUE.get());
727        }
728      }
729    
730    
731    
732      /**
733       * Reads an ASN.1 octet string element from the input stream and returns the
734       * value as a byte array.
735       *
736       * @return  The byte array value of the ASN.1 octet string element read, or
737       *          {@code null} if the end of the input stream was reached before any
738       *          data could be read.  If {@code null} is returned, then the input
739       *          stream will have been closed.
740       *
741       * @throws  IOException  If a problem occurs while reading from the input
742       *                       stream, if the end of the input stream is reached in
743       *                       the middle of the element, or or if an attempt is
744       *                       made to read an element larger than the maximum
745       *                       allowed size.
746       */
747      public byte[] readBytes()
748             throws IOException
749      {
750        final int type = readType();
751        if (type < 0)
752        {
753          return null;
754        }
755    
756        final int length = readLength();
757    
758        int valueBytesRead = 0;
759        int bytesRemaining = length;
760        final byte[] value = new byte[length];
761        while (valueBytesRead < length)
762        {
763          final int bytesRead = read(false, value, valueBytesRead, bytesRemaining);
764          if (bytesRead < 0)
765          {
766            throw new IOException(ERR_READ_END_BEFORE_VALUE_END.get());
767          }
768    
769          valueBytesRead += bytesRead;
770          bytesRemaining -= bytesRead;
771        }
772    
773        totalBytesRead += length;
774        return value;
775      }
776    
777    
778    
779      /**
780       * Reads an ASN.1 octet string element from the input stream and returns the
781       * value as a {@code String} using the UTF-8 encoding.
782       *
783       * @return  The {@code String} value of the ASN.1 octet string element read,
784       *          or {@code null} if the end of the input stream was reached before
785       *          any data could be read.  If {@code null} is returned, then the
786       *          input stream will have been closed.
787       *
788       * @throws  IOException  If a problem occurs while reading from the input
789       *                       stream, if the end of the input stream is reached in
790       *                       the middle of the element, or or if an attempt is
791       *                       made to read an element larger than the maximum
792       *                       allowed size.
793       */
794      public String readString()
795             throws IOException
796      {
797        final int type = readType();
798        if (type < 0)
799        {
800          return null;
801        }
802    
803        final int length = readLength();
804    
805        int valueBytesRead = 0;
806        int bytesRemaining = length;
807        final byte[] value = new byte[length];
808        while (valueBytesRead < length)
809        {
810          final int bytesRead = read(false, value, valueBytesRead, bytesRemaining);
811          if (bytesRead < 0)
812          {
813            throw new IOException(ERR_READ_END_BEFORE_VALUE_END.get());
814          }
815    
816          valueBytesRead += bytesRead;
817          bytesRemaining -= bytesRead;
818        }
819    
820        totalBytesRead += length;
821        return toUTF8String(value);
822      }
823    
824    
825    
826      /**
827       * Reads the beginning of an ASN.1 sequence from the input stream and
828       * returns a value that can be used to determine when the end of the sequence
829       * has been reached.  Elements which are part of the sequence may be read from
830       * this ASN.1 stream reader until the
831       * {@link ASN1StreamReaderSequence#hasMoreElements} method returns
832       * {@code false}.
833       *
834       * @return  An object which may be used to determine when the end of the
835       *          sequence has been reached, or {@code null} if the end of the input
836       *          stream was reached before any data could be read.  If {@code null}
837       *          is returned, then the input stream will have been closed.
838       *
839       * @throws  IOException  If a problem occurs while reading from the input
840       *                       stream, if the end of the input stream is reached in
841       *                       the middle of the element, or or if an attempt is
842       *                       made to read an element larger than the maximum
843       *                       allowed size.
844       */
845      public ASN1StreamReaderSequence beginSequence()
846             throws IOException
847      {
848        final int type = readType();
849        if (type < 0)
850        {
851          return null;
852        }
853    
854        final int length = readLength();
855    
856        return new ASN1StreamReaderSequence(this, (byte) type, length);
857      }
858    
859    
860    
861      /**
862       * Reads the beginning of an ASN.1 set from the input stream and returns a
863       * value that can be used to determine when the end of the set has been
864       * reached.  Elements which are part of the set may be read from this ASN.1
865       * stream reader until the {@link ASN1StreamReaderSet#hasMoreElements} method
866       * returns {@code false}.
867       *
868       * @return  An object which may be used to determine when the end of the set
869       *          has been reached, or {@code null} if the end of the input stream
870       *          was reached before any data could be read.  If {@code null} is
871       *          returned, then the input stream will have been closed.
872       *
873       * @throws  IOException  If a problem occurs while reading from the input
874       *                       stream, if the end of the input stream is reached in
875       *                       the middle of the element, or or if an attempt is
876       *                       made to read an element larger than the maximum
877       *                       allowed size.
878       */
879      public ASN1StreamReaderSet beginSet()
880             throws IOException
881      {
882        final int type = readType();
883        if (type < 0)
884        {
885          return null;
886        }
887    
888        final int length = readLength();
889    
890        return new ASN1StreamReaderSet(this, (byte) type, length);
891      }
892    
893    
894    
895      /**
896       * Reads a byte of data from the underlying input stream, optionally ignoring
897       * socket timeout exceptions.
898       *
899       * @param  initial  Indicates whether this is the initial read for an element.
900       *
901       * @return  The byte read from the input stream, or -1 if the end of the
902       *          input stream was reached.
903       *
904       * @throws  IOException  If a problem occurs while reading data.
905       */
906      private int read(final boolean initial)
907              throws IOException
908      {
909        try
910        {
911          return inputStream.read();
912        }
913        catch (SocketTimeoutException ste)
914        {
915          debugException(Level.FINEST, ste);
916    
917          if ((initial && ignoreInitialSocketTimeout) ||
918              ((! initial) && ignoreSubsequentSocketTimeout))
919          {
920            while (true)
921            {
922              try
923              {
924                return inputStream.read();
925              }
926              catch (SocketTimeoutException ste2)
927              {
928                debugException(Level.FINEST, ste2);
929              }
930            }
931          }
932          else
933          {
934            throw ste;
935          }
936        }
937      }
938    
939    
940    
941      /**
942       * Reads data from the underlying input stream, optionally ignoring socket
943       * timeout exceptions.
944       *
945       * @param  initial  Indicates whether this is the initial read for an element.
946       * @param  buffer   The buffer into which the data should be read.
947       * @param  offset   The position at which to start placing the data that was
948       *                  read.
949       * @param  length   The maximum number of bytes to read.
950       *
951       * @return  The number of bytes read, or -1 if the end of the input stream
952       *          was reached.
953       *
954       * @throws  IOException  If a problem occurs while reading data.
955       */
956      private int read(final boolean initial, final byte[] buffer, final int offset,
957                       final int length)
958              throws IOException
959      {
960        try
961        {
962          return inputStream.read(buffer, offset, length);
963        }
964        catch (SocketTimeoutException ste)
965        {
966          debugException(Level.FINEST, ste);
967          if ((initial && ignoreInitialSocketTimeout) ||
968              ((! initial) && ignoreSubsequentSocketTimeout))
969          {
970            while (true)
971            {
972              try
973              {
974                return inputStream.read(buffer, offset, length);
975              }
976              catch (SocketTimeoutException ste2)
977              {
978                debugException(Level.FINEST, ste2);
979              }
980            }
981          }
982          else
983          {
984            throw ste;
985          }
986        }
987      }
988    }