File: Signing\Content\KeyPairFileReader.cs
Web Access
Project: src\src\nuget-client\src\NuGet.Core\NuGet.Packaging\NuGet.Packaging.csproj (NuGet.Packaging)
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Text.RegularExpressions;

namespace NuGet.Packaging.Signing
{
    public class KeyPairFileReader : IDisposable
    {
        private static readonly Regex NamePattern = new Regex("^[a-zA-Z0-9\\.\\-/]+$", RegexOptions.CultureInvariant);

        private readonly StreamReader _reader;
        private bool _disposed;

        public KeyPairFileReader(Stream stream, Encoding encoding)
        {
            if (stream == null)
            {
                throw new ArgumentNullException(nameof(stream));
            }

            if (encoding == null)
            {
                throw new ArgumentNullException(nameof(encoding));
            }

            _reader = new StreamReader(stream, encoding, detectEncodingFromByteOrderMarks: false);
        }

        /// <summary>
        /// Read a section of key value pairs from the file.
        /// Throw for invalid formats.
        /// </summary>
        /// <remarks>Returns an empty set if the file has reached the end.</remarks>
        public Dictionary<string, string> ReadSection()
        {
            var entries = new Dictionary<string, string>(StringComparer.Ordinal);

            var line = _reader.ReadLine();

            if (line == null)
            {
                return entries;
            }

            while (!string.IsNullOrEmpty(line))
            {
                var property = GetProperty(line);

                if (entries.ContainsKey(property.Key))
                {
                    ThrowInvalidFormat();
                }
                else
                {
                    entries.Add(property.Key, property.Value);
                }

                line = _reader.ReadLine();
            }

            // Read section break.
            if (line != string.Empty)
            {
                ThrowInvalidFormat();
            }

            return entries;
        }

        private static KeyValuePair<string, string> GetProperty(string line)
        {
#if NETCOREAPP
            var pos = line.IndexOf(':', StringComparison.Ordinal);
#else
            var pos = line.IndexOf(':');
#endif

            if (pos > 0)
            {
                var key = line.Substring(0, pos);

                if (NamePattern.IsMatch(key))
                {
                    var value = line.Substring(pos + 1);

                    if (!string.IsNullOrEmpty(value))
                    {
                        return new KeyValuePair<string, string>(key, value);
                    }
                }
            }

            throw new SignatureException(Strings.InvalidSignatureContent);
        }

        private static void ThrowInvalidFormat()
        {
            throw new SignatureException(Strings.InvalidSignatureContent);
        }

        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

        protected virtual void Dispose(bool disposing)
        {
            if (_disposed)
            {
                return;
            }

            if (disposing)
            {
                _reader.Dispose();
            }

            _disposed = true;
        }
    }
}