File: Internal\StreamMarshaler.cs
Web Access
Project: src\src\runtime\src\libraries\System.Speech\src\System.Speech.csproj (System.Speech)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.IO;
using System.Runtime.InteropServices;
using System.Text;

namespace System.Speech.Internal
{
    internal sealed class StreamMarshaler : IDisposable
    {
        #region Constructors

        internal StreamMarshaler(Stream stream)
        {
            _stream = stream;
        }

        public void Dispose()
        {
            _safeHMem.Dispose();
        }

        #endregion

        #region internal Methods
        internal void ReadArray<T>(T[] ao, int c)
            where T : struct
        {
            int sizeOfOne = Marshal.SizeOf<T>();
            int sizeObject = sizeOfOne * c;
            byte[] ab = Helpers.ReadStreamToByteArray(_stream, sizeObject);

            IntPtr buffer = _safeHMem.Buffer(sizeObject);

            Marshal.Copy(ab, 0, buffer, sizeObject);
            for (int i = 0; i < c; i++)
            {
                ao[i] = Marshal.PtrToStructure<T>((nint)buffer + (nint)i * sizeOfOne);
            }
        }

        internal void WriteArray<T>(T[] ao, int c)
            where T : notnull
        {
            int sizeOfOne = Marshal.SizeOf<T>();
            int sizeObject = sizeOfOne * c;
            byte[] ab = new byte[sizeObject];
            IntPtr buffer = _safeHMem.Buffer(sizeObject);

            for (int i = 0; i < c; i++)
            {
                Marshal.StructureToPtr<T>(ao[i], (nint)buffer + (nint)i * sizeOfOne, false);
            }

            Marshal.Copy(buffer, ab, 0, sizeObject);
            _stream.Write(ab, 0, sizeObject);
        }

        internal void ReadArrayChar(char[] ach, int c)
        {
            int sizeObject = c * Helpers._sizeOfChar;

            if (sizeObject > 0)
            {
                byte[] ab = Helpers.ReadStreamToByteArray(_stream, sizeObject);

                IntPtr buffer = _safeHMem.Buffer(sizeObject);

                Marshal.Copy(ab, 0, buffer, sizeObject);
                Marshal.Copy(buffer, ach, 0, c);
            }
        }

#pragma warning disable 56518 // BinaryReader can't be disposed because underlying stream still in use.

        // Helper method to read a Unicode string from a stream.
        internal string ReadNullTerminatedString()
        {
            BinaryReader br = new(_stream, Encoding.Unicode);
            StringBuilder stringBuilder = new();

            while (true)
            {
                char c = br.ReadChar();
                if (c == '\0')
                {
                    break;
                }
                else
                {
                    stringBuilder.Append(c);
                }
            }
            return stringBuilder.ToString();
        }

#pragma warning restore 56518

        internal void WriteArrayChar(char[] ach, int c)
        {
            int sizeObject = c * Helpers._sizeOfChar;

            if (sizeObject > 0)
            {
                byte[] ab = new byte[sizeObject];
                IntPtr buffer = _safeHMem.Buffer(sizeObject);

                Marshal.Copy(ach, 0, buffer, c);
                Marshal.Copy(buffer, ab, 0, sizeObject);
                _stream.Write(ab, 0, sizeObject);
            }
        }

        internal void ReadStream<T>(T o)
            where T : notnull
        {
            int sizeObject = Marshal.SizeOf<T>();
            byte[] ab = Helpers.ReadStreamToByteArray(_stream, sizeObject);

            IntPtr buffer = _safeHMem.Buffer(sizeObject);

            Marshal.Copy(ab, 0, buffer, sizeObject);
            Marshal.PtrToStructure<T>(buffer, o);
        }

        internal void WriteStream<T>(T o)
            where T : notnull
        {
            int sizeObject = Marshal.SizeOf<T>();
            byte[] ab = new byte[sizeObject];
            IntPtr buffer = _safeHMem.Buffer(sizeObject);

            Marshal.StructureToPtr<T>(o, buffer, false);
            Marshal.Copy(buffer, ab, 0, sizeObject);

            // Read the Header
            _stream.Write(ab, 0, sizeObject);
        }

        #endregion

        #region internal Fields

        internal Stream Stream
        {
            get
            {
                return _stream;
            }
        }

        internal uint Position
        {
            set
            {
                _stream.Position = value;
            }
        }

        #endregion

        #region Private Fields

        private HGlobalSafeHandle _safeHMem = new();

        private Stream _stream;

        #endregion
    }
}