/// <summary> /// Reads exactly the specified number of bytes from a stream. /// </summary> /// /// <param name="stream">The stream to read from.</param> /// <param name="buffer">The array in which to store bytes.</param> /// <param name="offset">The index in <paramref name="buffer"/> of the first byte to /// store.</param> /// <param name="count">The number of bytes to store.</param> /// <param name="throwIfNoData"><c>true</c> to throw an exception if the end of the stream /// is reached before reading any data. If <c>false</c>, this method returns /// <c>false</c> instead of throwing an exception. An exception is always thrown if /// one or more bytes were read before reaching the end of the stream.</param> /// /// <returns><c>true</c> if the requested number of bytes were read from the underlying /// stream, or <c>false</c> if the end of the stream was reached without reading any /// bytes and <paramref name="throwIfNoData"/> is <c>true</c>.</returns> /// /// <exception cref="ArgumentNullException"><paramref name="stream"/> or /// <paramref name="buffer"/> are <c>null</c>.</exception> /// <exception cref="ArgumentOutOfRangeException">The specified /// <paramref name="offset"/> and <paramref name="count"/> fall outside the bounds of /// the <paramref name="buffer"/> array.</exception> /// <exception cref="EndOfStreamException">The end of the stream was reached before the /// requested number of bytes were read, and <paramref name="throwIfNoData"/> is /// <c>true</c>.</exception> /// <exception cref="IOException">An I/O error occurred.</exception> /// <exception cref="NotSupportedException">The stream does not support /// reading.</exception> /// <exception cref="ObjectDisposedException">The stream object has been /// disposed.</exception> public static bool ReadExactly(this Stream stream, byte[] buffer, int offset, int count, bool throwIfNoData) { if (stream == null) { throw new ArgumentNullException(nameof(stream)); } ValidationUtilities.ValidateArraySlice(buffer, offset, count, nameof(buffer), nameof(offset), nameof(count)); int totalBytesRead = 0; while (count > 0) { int bytesRead = stream.Read(buffer, offset, count); Debug.Assert(bytesRead >= 0 && bytesRead <= count); if (bytesRead == 0) { if (!throwIfNoData && totalBytesRead == 0) { return(false); } throw new EndOfStreamException(); } count -= bytesRead; offset += bytesRead; totalBytesRead += bytesRead; } return(true); }
/// <summary> /// Reads concatenated data from the underlying sequence of source readers. /// </summary> /// /// <param name="buffer">The array in which to store data.</param> /// <param name="index">The index in <paramref name="buffer"/> of the first byte to /// store.</param> /// <param name="count">The maximum number of bytes to store.</param> /// /// <returns>The actual number of bytes read, which may be less than the amount requested /// or zero if the end of the concatenated sources is reached.</returns> /// /// <exception cref="ArgumentNullException"><paramref name="buffer"/> is /// <c>null</c>.</exception> /// <exception cref="ArgumentOutOfRangeException"><paramref name="index"/> or /// <paramref name="count"/> are negative or fall outside the array /// bounds.</exception> /// <exception cref="IOException">An I/O error occurred.</exception> /// <exception cref="ObjectDisposedException">This reader or one or more source readers /// have been disposed.</exception> public override int Read(char[] buffer, int index, int count) { if (_sources == null) { throw new ObjectDisposedException(GetType().Name); } ValidationUtilities.ValidateArraySlice(buffer, index, count, nameof(buffer), nameof(index), nameof(count)); int total = 0; while (count > 0) { if (_sources.Count == 0) { return(total); } int bytesRead = _sources.Peek().Read(buffer, index, count); if (bytesRead == 0) { _sources.Dequeue().Dispose(); } total += bytesRead; count -= bytesRead; index += bytesRead; } return(total); }
/// <summary> /// Initializes a new data stream using the specified data. /// </summary> /// /// <param name="data">The array to wrap.</param> /// <param name="offset">The index of the first byte to wrap.</param> /// <param name="count">The number of bytes to wrap.</param> /// /// <exception cref="ArgumentNullException"><paramref name="data"/> is /// <c>null</c>.</exception> /// <exception cref="ArgumentOutOfRangeException"><paramref name="offset"/> and/or /// <paramref name="count"/> fall outside the bounds of the array.</exception> public ProtocolReader(byte[] data, int offset, int count) { ValidationUtilities.ValidateArraySlice(data, offset, count, nameof(data), nameof(offset), nameof(count)); _buffer = data; _position = _originalPosition = offset; _endPosition = offset + count; }
/// <summary> /// Updates the CRC value by processing the specified data. /// </summary> /// /// <param name="buffer">An array containing the bytes to process.</param> /// <param name="offset">The index in <paramref name="buffer"/> of the first byte to /// process.</param> /// <param name="count">The number of bytes to process.</param> /// /// <exception cref="ArgumentNullException"><paramref name="buffer"/> is /// <c>null</c>.</exception> /// <exception cref="ArgumentOutOfRangeException">The specified <paramref name="offset"/> /// and <paramref name="count"/> fall outside the bounds of the array.</exception> public void Update(byte[] buffer, int offset, int count) { ValidationUtilities.ValidateArraySlice(buffer, offset, count, nameof(buffer), nameof(offset), nameof(count)); for (int i = 0; i < count; ++i) { _crc = LOOKUP[(_crc ^ buffer[offset + i]) & 0xFF] ^ (_crc >> 8); } }
/// <summary> /// Asynchronously reads up to <paramref name="count"/> bytes from the underlying stream /// at the current subset position. /// </summary> /// /// <param name="buffer">The array in which to store bytes.</param> /// <param name="offset">The index in <paramref name="buffer"/> of the first byte to /// store.</param> /// <param name="count">The maximum number of bytes to read and store.</param> /// <param name="cancellationToken">A cancellation token.</param> /// /// <returns>The number of bytes actually read and stored, which may be less than /// <paramref name="count"/> or zero if the end of the stream has been /// reached.</returns> /// /// <exception cref="ArgumentNullException"><paramref name="buffer"/> is /// <c>null</c>.</exception> /// <exception cref="ArgumentOutOfRangeException"><paramref name="offset"/> or /// <paramref name="count"/> exceed the bounds of /// <paramref name="buffer"/>.</exception> /// <exception cref="IOException">An I/O error occurred.</exception> /// <exception cref="ObjectDisposedException">This object or the underlying stream have /// been disposed.</exception> public override async Task <int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) { ValidationUtilities.ValidateArraySlice(buffer, offset, count, nameof(buffer), nameof(offset), nameof(count)); ThrowIfDisposed(); if (_locker != null) { Monitor.Enter(_locker); } try { if (_position > _length) { return(0); } if (_length - _position <= int.MaxValue) { count = Math.Min(count, (int)(_length - _position)); } if (count == 0) { return(0); } if (_stream.Position != _offset + _position) { _stream.Seek(_offset + _position, SeekOrigin.Begin); } int bytesRead = await _stream.ReadAsync(buffer, offset, count, cancellationToken).ConfigureAwait(false); _position += bytesRead; return(bytesRead); } finally { if (_locker != null) { Monitor.Exit(_locker); } } }
/// <summary> /// Reads exactly the specified number of bytes from a stream. /// </summary> /// /// <param name="stream">The stream to read from.</param> /// <param name="buffer">The array in which to store bytes.</param> /// <param name="offset">The index in <paramref name="buffer"/> of the first byte to /// store.</param> /// <param name="count">The number of bytes to store.</param> /// <param name="throwIfNoData"><c>true</c> to throw an exception if the end of the stream /// is reached before reading any data. If <c>false</c>, this method returns /// <c>false</c> instead of throwing an exception. An exception is always thrown if /// one or more bytes were read before reaching the end of the stream.</param> /// <param name="cancellationToken">A cancellation token.</param> /// /// <returns><c>true</c> if the requested number of bytes were read from the underlying /// stream, or <c>false</c> if the end of the stream was reached without reading any /// bytes and <paramref name="throwIfNoData"/> is <c>true</c>.</returns> /// /// <exception cref="ArgumentNullException"><paramref name="stream"/>, /// <paramref name="buffer"/> or <paramref name="cancellationToken"/> are /// <c>null</c>.</exception> /// <exception cref="ArgumentOutOfRangeException">The specified /// <paramref name="offset"/> and <paramref name="count"/> fall outside the bounds of /// the <paramref name="buffer"/> array.</exception> /// <exception cref="EndOfStreamException">The end of the stream was reached before the /// requested number of bytes were read, and <paramref name="throwIfNoData"/> is /// <c>true</c>.</exception> /// <exception cref="IOException">An I/O error occurred.</exception> /// <exception cref="NotSupportedException">The stream does not support /// reading.</exception> /// <exception cref="ObjectDisposedException">The stream object has been /// disposed.</exception> public static async Task <bool> ReadExactlyAsync(this Stream stream, byte[] buffer, int offset, int count, bool throwIfNoData, CancellationToken cancellationToken) { if (stream == null) { throw new ArgumentNullException(nameof(stream)); } if (cancellationToken == null) { throw new ArgumentNullException(nameof(cancellationToken)); } ValidationUtilities.ValidateArraySlice(buffer, offset, count, nameof(buffer), nameof(offset), nameof(count)); int totalBytesRead = 0; while (count > 0) { int bytesRead = await stream.ReadAsync(buffer, offset, count, cancellationToken).ConfigureAwait(false); Debug.Assert(bytesRead >= 0 && bytesRead <= count); if (bytesRead == 0) { if (!throwIfNoData && totalBytesRead == 0) { return(false); } throw new EndOfStreamException(); } count -= bytesRead; offset += bytesRead; totalBytesRead += bytesRead; } return(true); }
/// <summary> /// Parses the specified data and returns a <see cref="BitmapImage"/>. /// </summary> /// /// <param name="data">An array containing the image data bytes.</param> /// <param name="offset">The index in <paramref name="data"/> of the first image data /// byte.</param> /// <param name="count">The number of image data bytes.</param> /// /// <returns>A new <see cref="BitmapImage"/> object.</returns> /// /// <exception cref="ArgumentNullException"><paramref name="data"/> is /// <c>null</c>.</exception> /// <exception cref="ArgumentOutOfRangeException"><paramref name="offset"/> and /// <paramref name="count"/> are outside the bounds of the array.</exception> /// <exception cref="InvalidDataException">The image data cannot be /// parsed.</exception> public static BitmapImage ParseBitmap(byte[] data, int offset, int count) { ValidationUtilities.ValidateArraySlice(data, offset, count, nameof(data), nameof(offset), nameof(count)); using (MemoryStream memory = new MemoryStream(data, offset, count)) { try { BitmapImage image = new BitmapImage(); image.BeginInit(); image.CacheOption = BitmapCacheOption.OnLoad; image.StreamSource = memory; image.EndInit(); return(image); } catch (Exception ex) { throw new InvalidDataException("Failed to parse image data", ex); } } }