def read(self, size=None):
    """Reads a byte string from the file-like object at the current offset.

    The function will read a byte string of the specified size or
    all of the remaining data if no size was specified.

    Args:
      size (Optional[int]): number of bytes to read, where None is all
          remaining data.

    Returns:
      bytes: data read.

    Raises:
      IOError: if the read failed.
      OSError: if the read failed.
    """
    if not self._is_open:
      raise IOError('Not opened.')

    if self._current_offset < 0:
      raise IOError(
          'Invalid current offset: {0:d} value less than zero.'.format(
              self._current_offset))

    if self._decrypted_stream_size is None:
      self._decrypted_stream_size = self._GetDecryptedStreamSize()

    if self._decrypted_stream_size < 0:
      raise IOError('Invalid decrypted stream size.')

    if self._current_offset >= self._decrypted_stream_size:
      return b''

    if self._realign_offset:
      self._AlignDecryptedDataOffset(self._current_offset)
      self._realign_offset = False

    if size is None:
      size = self._decrypted_stream_size
    if self._current_offset + size > self._decrypted_stream_size:
      size = self._decrypted_stream_size - self._current_offset

    decrypted_data = b''

    if size == 0:
      return decrypted_data

    while size > self._decrypted_data_size:
      decrypted_data = b''.join([
          decrypted_data,
          self._decrypted_data[self._decrypted_data_offset:]])

      remaining_decrypted_data_size = (
          self._decrypted_data_size - self._decrypted_data_offset)

      self._current_offset += remaining_decrypted_data_size
      size -= remaining_decrypted_data_size

      if self._current_offset >= self._decrypted_stream_size:
        break

      read_count = self._ReadEncryptedData(self._ENCRYPTED_DATA_BUFFER_SIZE)
      self._decrypted_data_offset = 0
      if read_count == 0:
        break

    if size > 0:
      slice_start_offset = self._decrypted_data_offset
      slice_end_offset = slice_start_offset + size

      decrypted_data = b''.join([
          decrypted_data,
          self._decrypted_data[slice_start_offset:slice_end_offset]])

      self._decrypted_data_offset += size
      self._current_offset += size

    return decrypted_data
Reads a byte string from the file-like object at the current offset.

    The function will read a byte string of the specified size or
    all of the remaining data if no size was specified.

    Args:
      size (Optional[int]): number of bytes to read, where None is all
          remaining data.

    Returns:
      bytes: data read.

    Raises:
      IOError: if the read failed.
      OSError: if the read failed.