• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

JaCraig / Archivist / 19323535613

13 Nov 2025 07:11AM UTC coverage: 77.001% (-0.5%) from 77.456%
19323535613

push

github

web-flow
Merge pull request #223 from JaCraig/dependabot/nuget/dot-config/dependencies-d88ba084d1

fix: Bump the dependencies group with 2 updates

2403 of 3412 branches covered (70.43%)

Branch coverage included in aggregate %.

3178 of 3836 relevant lines covered (82.85%)

8728.59 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

76.32
/Archivist/BaseClasses/ReaderBaseClass.cs
1
using Archivist.Interfaces;
2
using Microsoft.Extensions.Logging;
3
using System;
4
using System.Buffers;
5
using System.Diagnostics.CodeAnalysis;
6
using System.IO;
7
using System.Threading.Tasks;
8

9
namespace Archivist.BaseClasses
10
{
11
    /// <summary>
12
    /// Base class for format readers.
13
    /// </summary>
14
    /// <seealso cref="IFormatReader"/>
15
    /// <remarks>Initializes a new instance of the <see cref="ReaderBaseClass"/> class.</remarks>
16
    /// <param name="logger">The logger to use for logging.</param>
17
    public abstract class ReaderBaseClass(ILogger? logger) : IFormatReader
389✔
18
    {
19
        /// <summary>
20
        /// Gets the header information for the format.
21
        /// </summary>
22
        public abstract byte[] HeaderInfo { get; }
23

24
        /// <summary>
25
        /// Gets the logger to use for logging.
26
        /// </summary>
27
        protected ILogger? Logger { get; } = logger;
474✔
28

29
        /// <summary>
30
        /// Determines whether the reader can read the specified stream.
31
        /// </summary>
32
        /// <param name="stream">The stream to read.</param>
33
        /// <returns><c>true</c> if the reader can read the stream; otherwise, <c>false</c>.</returns>
34
        public bool CanRead(Stream? stream)
35
        {
36
            if (!IsValidStream(stream))
24✔
37
            {
38
                Logger?.LogDebug("{readerName}.CanRead(): Stream is null or invalid.", GetType().Name);
22!
39
                return false;
22✔
40
            }
41
            if (HeaderInfo.Length == 0)
2!
42
                return InternalCanRead(stream);
×
43
            try
44
            {
45
                _ = stream.Seek(0, SeekOrigin.Begin);
2✔
46
                var StartIndex = FindStartIndex(stream);
2✔
47
                _ = stream.Seek(StartIndex, SeekOrigin.Begin);
2✔
48
                var Buffer = ArrayPool<byte>.Shared.Rent(HeaderInfo.Length);
2✔
49
                _ = stream.Read(Buffer, 0, Buffer.Length);
2✔
50
                _ = stream.Seek(0, SeekOrigin.Begin);
2✔
51
                for (var X = 0; X < HeaderInfo.Length; ++X)
26✔
52
                {
53
                    if (Buffer[X] != HeaderInfo[X])
12✔
54
                    {
55
                        ArrayPool<byte>.Shared.Return(Buffer);
1✔
56
                        return false;
1✔
57
                    }
58
                }
59
                ArrayPool<byte>.Shared.Return(Buffer);
1✔
60
                return InternalCanRead(stream);
1✔
61
            }
62
            catch (Exception Ex)
×
63
            {
64
                Logger?.LogError(Ex, "{readerName}.CanRead(): Error occurred while checking if the reader can read the stream.", GetType().Name);
×
65
                return false;
×
66
            }
67
        }
2✔
68

69
        /// <summary>
70
        /// Used to determine if a reader can actually read the file.
71
        /// </summary>
72
        /// <param name="stream">The stream to read.</param>
73
        /// <returns><c>true</c> if the reader can read the file; otherwise, <c>false</c>.</returns>
74
        public virtual bool InternalCanRead([NotNullWhen(true)] Stream? stream) => true;
6✔
75

76
        /// <summary>
77
        /// Reads the file asynchronously.
78
        /// </summary>
79
        /// <param name="stream">The stream to read.</param>
80
        /// <returns>
81
        /// A task representing the asynchronous operation that returns the generic file.
82
        /// </returns>
83
        public abstract Task<IGenericFile?> ReadAsync(Stream? stream);
84

85
        /// <summary>
86
        /// Validates if the provided stream is readable, has a non-zero length, and supports seeking.
87
        /// </summary>
88
        /// <param name="stream">The stream to validate.</param>
89
        /// <returns><c>true</c> if the stream is valid; otherwise, <c>false</c>.</returns>
90
        protected static bool IsValidStream([NotNullWhen(true)] Stream? stream)
91
        {
92
            if (stream?.CanRead != true)
126✔
93
                return false;
59✔
94
            if (stream.Length == 0)
67✔
95
                return false;
18✔
96
            if (!stream.CanSeek)
49!
97
                return false;
×
98
            try
99
            {
100
                var TempBuffer = ArrayPool<byte>.Shared.Rent(1);
49✔
101
                _ = stream.Seek(0, SeekOrigin.Begin);
49✔
102
                _ = stream.Read(TempBuffer, 0, 1);
49✔
103
                _ = stream.Seek(0, SeekOrigin.Begin);
49✔
104
                ArrayPool<byte>.Shared.Return(TempBuffer);
49✔
105
            }
49✔
106
            catch
×
107
            {
108
                return false;
×
109
            }
110
            return true;
49✔
111
        }
×
112

113
        /// <summary>
114
        /// Finds the start index of the file.
115
        /// </summary>
116
        /// <param name="stream">The stream to read.</param>
117
        /// <returns>The start index of the file.</returns>
118
        private static int FindStartIndex(Stream stream)
119
        {
120
            if (stream.Length < 3)
2!
121
                return 0;
×
122
            var BOMBuffer = ArrayPool<byte>.Shared.Rent(3);
2✔
123
            _ = stream.Read(BOMBuffer, 0, BOMBuffer.Length);
2✔
124
            _ = stream.Seek(0, SeekOrigin.Begin);
2✔
125
            var ReturnValue = BOMBuffer[0] == 0xEF && BOMBuffer[1] == 0xBB && BOMBuffer[2] == 0xBF ? 3 : 0;
2!
126
            ArrayPool<byte>.Shared.Return(BOMBuffer);
2✔
127
            return ReturnValue;
2✔
128
        }
129
    }
130
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc