code: public int read() throws IOException {
          int b = 0;
  
          // Byte to be read is already in out buffer, simply returning it
          if (fOffset < fLength) {
              return fData[fOffset++] & 0xff;
          }
  
          /*
           * End of the stream is reached.
           * I also believe that in certain cases fOffset can point to the
           * position after the end of stream, for example, after invalid
           * `setStartOffset()` call followed by `rewind()`.
           * This situation is not handled currently.
           */
          if (fOffset == fEndOffset) {
              return -1;
          }
  
          /*
           * Ok, we should actually read data from underlying stream, but
           * first it will be good to check if buffer array should be
           * expanded. Each time buffer size is doubled.
           */
          if (fOffset == fData.length) {
              byte[] newData = new byte[fOffset << 1];
              System.arraycopy(fData, 0, newData, 0, fOffset);
              fData = newData;
          }
  
          // Reading byte from the underlying stream, storing it in buffer and
          // then returning it.
          b = fInputStream.read();
  
          if (b == -1) {
              fEndOffset = fOffset;
  
              return -1;
          }
  
          fData[fLength++] = (byte) b;
          fOffset++;
  
          return b & 0xff;
      }
docs: Reads next byte from this stream. This byte is either being read from underlying InputStream
  or taken from the internal buffer in case it was already read at some point before.
  
  @return Next byte of data or <code>-1</code> if end of stream is reached.
  @throws IOException in case of any I/O errors.