aboutsummaryrefslogtreecommitdiff
path: root/src/Ryujinx.Common/Extensions/StreamExtensions.cs
blob: 431d5534a9fe25763b6027368e10d9a6710c00f0 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
using System;
using System.Buffers.Binary;
using System.IO;
using System.Runtime.InteropServices;

namespace Ryujinx.Common
{
    public static class StreamExtensions
    {
        /// <summary>
        /// Writes a <cref="ReadOnlySpan<int>" /> to this stream.
        ///
        /// This default implementation converts each buffer value to a stack-allocated
        /// byte array, then writes it to the Stream using <cref="System.Stream.Write(byte[])" />.
        /// </summary>
        /// <param name="stream">The stream to be written to</param>
        /// <param name="buffer">The buffer of values to be written</param>
        public static void Write(this Stream stream, ReadOnlySpan<int> buffer)
        {
            if (buffer.Length == 0)
            {
                return;
            }

            if (BitConverter.IsLittleEndian)
            {
                ReadOnlySpan<byte> byteBuffer = MemoryMarshal.Cast<int, byte>(buffer);
                stream.Write(byteBuffer);
            }
            else
            {
                Span<byte> byteBuffer = stackalloc byte[sizeof(int)];

                foreach (int value in buffer)
                {
                    BinaryPrimitives.WriteInt32LittleEndian(byteBuffer, value);
                    stream.Write(byteBuffer);
                }
            }
        }

        /// <summary>
        /// Writes a four-byte signed integer to this stream. The current position
        /// of the stream is advanced by four.
        /// </summary>
        /// <param name="stream">The stream to be written to</param>
        /// <param name="value">The value to be written</param>
        public static void Write(this Stream stream, int value)
        {
            Span<byte> buffer = stackalloc byte[sizeof(int)];
            BinaryPrimitives.WriteInt32LittleEndian(buffer, value);
            stream.Write(buffer);
        }

        /// <summary>
        /// Writes an eight-byte signed integer to this stream. The current position
        /// of the stream is advanced by eight.
        /// </summary>
        /// <param name="stream">The stream to be written to</param>
        /// <param name="value">The value to be written</param>
        public static void Write(this Stream stream, long value)
        {
            Span<byte> buffer = stackalloc byte[sizeof(long)];
            BinaryPrimitives.WriteInt64LittleEndian(buffer, value);
            stream.Write(buffer);
        }

        /// <summary>
        // Writes a four-byte unsigned integer to this stream. The current position
        // of the stream is advanced by four.
        /// </summary>
        /// <param name="stream">The stream to be written to</param>
        /// <param name="value">The value to be written</param>
        public static void Write(this Stream stream, uint value)
        {
            Span<byte> buffer = stackalloc byte[sizeof(uint)];
            BinaryPrimitives.WriteUInt32LittleEndian(buffer, value);
            stream.Write(buffer);
        }

        /// <summary>
        /// Writes an eight-byte unsigned integer to this stream. The current
        /// position of the stream is advanced by eight.
        /// </summary>
        /// <param name="stream">The stream to be written to</param>
        /// <param name="value">The value to be written</param>
        public static void Write(this Stream stream, ulong value)
        {
            Span<byte> buffer = stackalloc byte[sizeof(ulong)];
            BinaryPrimitives.WriteUInt64LittleEndian(buffer, value);
            stream.Write(buffer);
        }

        /// <summary>
        /// Writes the contents of source to stream by calling source.CopyTo(stream).
        /// Provides consistency with other Stream.Write methods.
        /// </summary>
        /// <param name="stream">The stream to be written to</param>
        /// <param name="source">The stream to be read from</param>
        public static void Write(this Stream stream, Stream source)
        {
            source.CopyTo(stream);
        }

        /// <summary>
        /// Writes a sequence of bytes to the Stream.
        /// </summary>
        /// <param name="stream">The stream to be written to.</param>
        /// <param name="value">The byte to be written</param>
        /// <param name="count">The number of times the value should be written</param>
        public static void WriteByte(this Stream stream, byte value, int count)
        {
            if (count <= 0)
            {
                return;
            }

            const int BlockSize = 16;

            int blockCount = count / BlockSize;
            if (blockCount > 0)
            {
                Span<byte> span = stackalloc byte[BlockSize];
                span.Fill(value);
                for (int x = 0; x < blockCount; x++)
                {
                    stream.Write(span);
                }
            }

            int nonBlockBytes = count % BlockSize;
            for (int x = 0; x < nonBlockBytes; x++)
            {
                stream.WriteByte(value);
            }
        }
    }
}