示例#1
0
        }  // ReadAsync_MemoryStream

        internal static IAsyncOperationWithProgress <IBuffer, uint> ReadAsync_AbstractStream(Stream stream, IBuffer buffer, uint count,
                                                                                             InputStreamOptions options)
        {
            Debug.Assert(stream != null);
            Debug.Assert(stream.CanRead);
            Debug.Assert(buffer != null);
            Debug.Assert(0 <= count);
            Debug.Assert(count <= int.MaxValue);
            Debug.Assert(count <= buffer.Capacity);
            Debug.Assert(options == InputStreamOptions.None || options == InputStreamOptions.Partial || options == InputStreamOptions.ReadAhead);

            int bytesrequested = (int)count;

            // Check if the buffer is our implementation.
            // IF YES: In that case, we can read directly into its data array.
            // IF NO:  The buffer is of unknown implementation. It's not backed by a managed array, but the wrapped stream can only
            //         read into a managed array. If we used the user-supplied buffer we would need to copy data into it after every read.
            //         The spec allows to return a buffer instance that is not the same as passed by the user. So, we will create an own
            //         buffer instance, read data *directly* into the array backing it and then return it to the user.
            //         Note: the allocation costs we are paying for the new buffer are unavoidable anyway, as we would need to create
            //         an array to read into either way.

            IBuffer dataBuffer = buffer as WindowsRuntimeBuffer;

            if (dataBuffer == null)
            {
                dataBuffer = WindowsRuntimeBuffer.Create((int)Math.Min((uint)int.MaxValue, buffer.Capacity));
            }

            // This operation delegate will we run inside of the returned IAsyncOperationWithProgress:
            Func <CancellationToken, IProgress <uint>, Task <IBuffer> > readOperation = async(cancelToken, progressListener) =>
            {
                // No bytes read yet:
                dataBuffer.Length = 0;

                // Get the buffer backing array:
                byte[] data;
                int    offset;
                bool   managedBufferAssert = dataBuffer.TryGetUnderlyingData(out data, out offset);
                Debug.Assert(managedBufferAssert);

                // Init tracking values:
                bool done           = cancelToken.IsCancellationRequested;
                int  bytesCompleted = 0;

                // Loop until EOS, cancelled or read enough data according to options:
                while (!done)
                {
                    int bytesread = 0;

                    try
                    {
                        // Read asynchronously:
                        bytesread = await stream.ReadAsync(data !, offset + bytesCompleted, bytesrequested - bytesCompleted, cancelToken)
                                    .ConfigureAwait(continueOnCapturedContext: false);

                        // We will continue here on a different thread when read async completed:
                        bytesCompleted += bytesread;
                        // We will handle a cancelation exception and re-throw all others:
                    }
                    catch (OperationCanceledException)
                    {
                        // We assume that cancelToken.IsCancellationRequested is has been set and simply proceed.
                        // (we check cancelToken.IsCancellationRequested later)
                        Debug.Assert(cancelToken.IsCancellationRequested);

                        // This is because if the cancellation came after we read some bytes we want to return the results we got instead
                        // of an empty cancelled task, so if we have not yet read anything at all, then we can throw cancellation:
                        if (bytesCompleted == 0 && bytesread == 0)
                        {
                            throw;
                        }
                    }

                    // Update target buffer:
                    dataBuffer.Length = (uint)bytesCompleted;

                    Debug.Assert(bytesCompleted <= bytesrequested);

                    // Check if we are done:
                    done = options == InputStreamOptions.Partial || // If no complete read was requested, any amount of data is OK
                           bytesread == 0 ||                          // this implies EndOfStream
                           bytesCompleted == bytesrequested ||        // read all requested bytes
                           cancelToken.IsCancellationRequested;       // operation was cancelled

                    // Call user Progress handler:
                    if (progressListener != null)
                    {
                        progressListener.Report(dataBuffer.Length);
                    }
                }  // while (!done)

                // If we got here, then no error was detected. Return the results buffer:
                return(dataBuffer);
            };  // readOperation

            return(AsyncInfo.Run <IBuffer, uint>(readOperation));
        }  // ReadAsync_AbstractStream
示例#2
0
        }  // ReadAsync_AbstractStream

        #endregion ReadAsync implementations


        #region WriteAsync implementations

        internal static IAsyncOperationWithProgress <uint, uint> WriteAsync_AbstractStream(Stream stream, IBuffer buffer)
        {
            Debug.Assert(stream != null);
            Debug.Assert(stream.CanWrite);
            Debug.Assert(buffer != null);

            // Choose the optimal writing strategy for the kind of buffer supplied:
            Func <CancellationToken, IProgress <uint>, Task <uint> > writeOperation;

            byte[] data;
            int    offset;

            // If buffer is backed by a managed array:
            if (buffer.TryGetUnderlyingData(out data, out offset))
            {
                writeOperation = async(cancelToken, progressListener) =>
                {
                    if (cancelToken.IsCancellationRequested)  // CancellationToken is non-nullable
                    {
                        return(0);
                    }

                    Debug.Assert(buffer.Length <= int.MaxValue);

                    int bytesToWrite = (int)buffer.Length;

                    await stream.WriteAsync(data, offset, bytesToWrite, cancelToken).ConfigureAwait(continueOnCapturedContext: false);

                    if (progressListener != null)
                    {
                        progressListener.Report((uint)bytesToWrite);
                    }

                    return((uint)bytesToWrite);
                };
                // Otherwise buffer is of an unknown implementation:
            }
            else
            {
                writeOperation = async(cancelToken, progressListener) =>
                {
                    if (cancelToken.IsCancellationRequested)  // CancellationToken is non-nullable
                    {
                        return(0);
                    }

                    uint   bytesToWrite = buffer.Length;
                    Stream dataStream   = buffer.AsStream();

                    int buffSize = 0x4000;
                    if (bytesToWrite < buffSize)
                    {
                        buffSize = (int)bytesToWrite;
                    }

                    if (buffSize > 0)
                    {
                        await dataStream.CopyToAsync(stream, buffSize, cancelToken).ConfigureAwait(continueOnCapturedContext: false);
                    }

                    if (progressListener != null)
                    {
                        progressListener.Report((uint)bytesToWrite);
                    }

                    return((uint)bytesToWrite);
                };
            }  // if-else

            // Construct and run the async operation:
            return(AsyncInfo.Run <uint, uint>(writeOperation));
        }  // WriteAsync_AbstractStream
        public static bool IsSameData(this IBuffer buffer, IBuffer otherBuffer)
        {
            if (buffer == null)
                throw new ArgumentNullException(nameof(buffer));

            Contract.EndContractBlock();

            if (otherBuffer == null)
                return false;

            if (buffer == otherBuffer)
                return true;

            Byte[] thisDataArr, otherDataArr;
            Int32 thisDataOffs, otherDataOffs;

            bool thisIsManaged = buffer.TryGetUnderlyingData(out thisDataArr, out thisDataOffs);
            bool otherIsManaged = otherBuffer.TryGetUnderlyingData(out otherDataArr, out otherDataOffs);

            if (thisIsManaged != otherIsManaged)
                return false;

            if (thisIsManaged)
                return (thisDataArr == otherDataArr) && (thisDataOffs == otherDataOffs);

            IBufferByteAccess thisBuff = (IBufferByteAccess)buffer;
            IBufferByteAccess otherBuff = (IBufferByteAccess)otherBuffer;

            unsafe
            {
                return (thisBuff.GetBuffer() == otherBuff.GetBuffer());
            }
        }
        public static void CopyTo(this IBuffer source, UInt32 sourceIndex, IBuffer destination, UInt32 destinationIndex, UInt32 count)
        {
            if (source == null) throw new ArgumentNullException(nameof(source));
            if (destination == null) throw new ArgumentNullException(nameof(destination));
            if (count < 0) throw new ArgumentOutOfRangeException(nameof(count));
            if (sourceIndex < 0) throw new ArgumentOutOfRangeException(nameof(sourceIndex));
            if (destinationIndex < 0) throw new ArgumentOutOfRangeException(nameof(destinationIndex));
            if (source.Capacity <= sourceIndex) throw new ArgumentException(SR.Argument_BufferIndexExceedsCapacity);
            if (source.Capacity - sourceIndex < count) throw new ArgumentException(SR.Argument_InsufficientSpaceInSourceBuffer);
            if (destination.Capacity <= destinationIndex) throw new ArgumentException(SR.Argument_BufferIndexExceedsCapacity);
            if (destination.Capacity - destinationIndex < count) throw new ArgumentException(SR.Argument_InsufficientSpaceInTargetBuffer);
            Contract.EndContractBlock();

            // If source are destination are backed by managed arrays, use the arrays instead of the pointers as it does not require pinning:
            Byte[] srcDataArr, destDataArr;
            Int32 srcDataOffs, destDataOffs;

            bool srcIsManaged = source.TryGetUnderlyingData(out srcDataArr, out srcDataOffs);
            bool destIsManaged = destination.TryGetUnderlyingData(out destDataArr, out destDataOffs);

            if (srcIsManaged && destIsManaged)
            {
                Debug.Assert(count <= Int32.MaxValue);
                Debug.Assert(sourceIndex <= Int32.MaxValue);
                Debug.Assert(destinationIndex <= Int32.MaxValue);

                Buffer.BlockCopy(srcDataArr, srcDataOffs + (Int32)sourceIndex, destDataArr, destDataOffs + (Int32)destinationIndex, (Int32)count);
                return;
            }

            IntPtr srcPtr, destPtr;

            if (srcIsManaged)
            {
                Debug.Assert(count <= Int32.MaxValue);
                Debug.Assert(sourceIndex <= Int32.MaxValue);

                destPtr = destination.GetPointerAtOffset(destinationIndex);
                Marshal.Copy(srcDataArr, srcDataOffs + (Int32)sourceIndex, destPtr, (Int32)count);
                return;
            }

            if (destIsManaged)
            {
                Debug.Assert(count <= Int32.MaxValue);
                Debug.Assert(destinationIndex <= Int32.MaxValue);

                srcPtr = source.GetPointerAtOffset(sourceIndex);
                Marshal.Copy(srcPtr, destDataArr, destDataOffs + (Int32)destinationIndex, (Int32)count);
                return;
            }

            srcPtr = source.GetPointerAtOffset(sourceIndex);
            destPtr = destination.GetPointerAtOffset(destinationIndex);
            MemCopy(srcPtr, destPtr, count);
        }
        public static void CopyTo(this Byte[] source, Int32 sourceIndex, IBuffer destination, UInt32 destinationIndex, Int32 count)
        {
            if (source == null) throw new ArgumentNullException(nameof(source));
            if (destination == null) throw new ArgumentNullException(nameof(destination));
            if (count < 0) throw new ArgumentOutOfRangeException(nameof(count));
            if (sourceIndex < 0) throw new ArgumentOutOfRangeException(nameof(sourceIndex));
            if (destinationIndex < 0) throw new ArgumentOutOfRangeException(nameof(destinationIndex));
            if (source.Length <= sourceIndex) throw new ArgumentException(SR.Argument_IndexOutOfArrayBounds, nameof(sourceIndex));
            if (source.Length - sourceIndex < count) throw new ArgumentException(SR.Argument_InsufficientArrayElementsAfterOffset);
            if (destination.Capacity - destinationIndex < count) throw new ArgumentException(SR.Argument_InsufficientSpaceInTargetBuffer);
            Contract.EndContractBlock();

            // If destination is backed by a managed array, use the array instead of the pointer as it does not require pinning:
            Byte[] destDataArr;
            Int32 destDataOffs;
            if (destination.TryGetUnderlyingData(out destDataArr, out destDataOffs))
            {
                Buffer.BlockCopy(source, sourceIndex, destDataArr, (int)(destDataOffs + destinationIndex), count);
                return;
            }

            IntPtr destPtr = destination.GetPointerAtOffset(destinationIndex);
            Marshal.Copy(source, sourceIndex, destPtr, count);
        }
        }  // ReadAsync_AbstractStream

        #endregion ReadAsync implementations


        #region WriteAsync implementations

        internal static IAsyncOperationWithProgress<UInt32, UInt32> WriteAsync_AbstractStream(Stream stream, IBuffer buffer)
        {
            Debug.Assert(stream != null);
            Debug.Assert(stream.CanWrite);
            Debug.Assert(buffer != null);
            Contract.EndContractBlock();

            // Choose the optimal writing strategy for the kind of buffer supplied:
            Func<CancellationToken, IProgress<UInt32>, Task<UInt32>> writeOperation;
            Byte[] data;
            Int32 offset;

            // If buffer is backed by a managed array:
            if (buffer.TryGetUnderlyingData(out data, out offset))
            {
                writeOperation = async (cancelToken, progressListener) =>
                {
                    if (cancelToken.IsCancellationRequested)  // CancellationToken is non-nullable
                        return 0;

                    Debug.Assert(buffer.Length <= Int32.MaxValue);

                    Int32 bytesToWrite = (Int32)buffer.Length;

                    await stream.WriteAsync(data, offset, bytesToWrite, cancelToken).ConfigureAwait(continueOnCapturedContext: false);

                    if (progressListener != null)
                        progressListener.Report((UInt32)bytesToWrite);

                    return (UInt32)bytesToWrite;
                };
                // Otherwise buffer is of an unknown implementation:
            }
            else
            {
                writeOperation = async (cancelToken, progressListener) =>
                {
                    if (cancelToken.IsCancellationRequested)  // CancellationToken is non-nullable
                        return 0;

                    UInt32 bytesToWrite = buffer.Length;
                    Stream dataStream = buffer.AsStream();

                    Int32 buffSize = 0x4000;
                    if (bytesToWrite < buffSize)
                        buffSize = (Int32)bytesToWrite;

                    await dataStream.CopyToAsync(stream, buffSize, cancelToken).ConfigureAwait(continueOnCapturedContext: false);

                    if (progressListener != null)
                        progressListener.Report((UInt32)bytesToWrite);

                    return (UInt32)bytesToWrite;
                };
            }  // if-else

            // Construct and run the async operation:
            return AsyncInfo.Run<UInt32, UInt32>(writeOperation);
        }  // WriteAsync_AbstractStream