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