File: Metadata\MetadataFileNameManager.cs
Web Access
Project: src\src\dotnet-svcutil\lib\src\dotnet-svcutil-lib.csproj (dotnet-svcutil-lib)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
 
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Text;
 
namespace Microsoft.Tools.ServiceModel.Svcutil.Metadata
{
    internal class MetadataFileNameManager
    {
        private const string DataContractXsdBaseNamespace = "http://schemas.datacontract.org/2004/07/";
 
        private List<string> _files = new List<string>();
        public IEnumerable<string> Files
        {
            get { return _files; }
        }
 
        public string AddFileName(string basePath, string fileName, string extension)
        {
            if (string.IsNullOrWhiteSpace(fileName))
            {
                throw new ArgumentNullException(nameof(fileName));
            }
 
            if (string.IsNullOrWhiteSpace(extension))
            {
                extension = string.Empty;
            }
 
            if (string.IsNullOrWhiteSpace(basePath))
            {
                basePath = Directory.GetCurrentDirectory();
            }
 
            var filePath = GetFilePath(basePath, fileName, extension);
 
            for (uint i = 1; i < uint.MaxValue; i++)
            {
                if (!_files.Any((f) => StringComparer.OrdinalIgnoreCase.Compare(f, filePath) == 0))
                {
                    _files.Add(filePath);
                    return filePath;
                }
 
                string uniqueFileName = fileName + i.ToString(NumberFormatInfo.InvariantInfo);
                string uniqueFileNameWithExtension = GetFileNameWithExtension(uniqueFileName, extension);
                filePath = Path.IsPathRooted(uniqueFileNameWithExtension) ? uniqueFileNameWithExtension : Path.Combine(basePath, uniqueFileNameWithExtension);
            }
 
            throw new InvalidOperationException(string.Format(MetadataResources.Culture, MetadataResources.ErrUnableToCreateUniqueFileNameFormat, GetFileNameWithExtension(fileName, extension)));
        }
 
        public string AddFromNamespace(string basePath, string schemaNamespace, string extension)
        {
            var filename = FileNameFromNS(schemaNamespace);
            return AddFileName(basePath, filename, extension);
        }
 
        public static string GetFilePath(string basePath, string fileName, string extension)
        {
            if (string.IsNullOrWhiteSpace(fileName))
            {
                throw new ArgumentNullException(nameof(fileName));
            }
 
            if (string.IsNullOrWhiteSpace(extension))
            {
                extension = string.Empty;
            }
 
            if (string.IsNullOrWhiteSpace(basePath))
            {
                basePath = Directory.GetCurrentDirectory();
            }
 
            var fileNameWithExtension = GetFileNameWithExtension(fileName, extension);
            var filePath = Path.IsPathRooted(fileNameWithExtension) ? fileNameWithExtension : Path.Combine(basePath, fileNameWithExtension);
            return filePath;
        }
 
        public static string GetFilePathFromNamespace(string basePath, string schemaNs, string extension)
        {
            var fileName = FileNameFromNS(schemaNs);
            var filePath = GetFilePath(basePath, fileName, extension);
            return filePath;
        }
 
        private static string FileNameFromNS(string ns)
        {
            StringBuilder fileNameBuilder = new StringBuilder();
 
            if (string.IsNullOrWhiteSpace(ns))
            {
                FileNameFromNS_Add(fileNameBuilder, "noNamespace");
            }
            else
            {
                if (Uri.TryCreate(ns, UriKind.RelativeOrAbsolute, out Uri nsUri))
                {
                    if (nsUri.IsAbsoluteUri)
                    {
                        string absoluteUriString = nsUri.AbsoluteUri;
                        if (absoluteUriString.StartsWith(DataContractXsdBaseNamespace, StringComparison.Ordinal))
                        {
                            int length = absoluteUriString.Length - DataContractXsdBaseNamespace.Length;
                            if (absoluteUriString.EndsWith("/", StringComparison.Ordinal))
                            {
                                length--;
                            }
                            if (length > 0)
                            {
                                FileNameFromNS_Add(fileNameBuilder, absoluteUriString.Substring(DataContractXsdBaseNamespace.Length, length).Replace('/', '.'));
                            }
                            else
                            {
                                FileNameFromNS_Add(fileNameBuilder, "schema");
                            }
                        }
                        else
                        {
                            FileNameFromNS_Add(fileNameBuilder, nsUri.Host);
                            string absolutePath = nsUri.AbsolutePath;
                            if (absolutePath.EndsWith("/", StringComparison.Ordinal))
                            {
                                absolutePath = absolutePath.Substring(0, absolutePath.Length - 1);
                            }
                            FileNameFromNS_Add(fileNameBuilder, absolutePath.Replace('/', '.'));
                        }
                    }
                    else
                    {
                        FileNameFromNS_Add(fileNameBuilder, nsUri.OriginalString.Replace('/', '.'));
                    }
                }
                else
                {
                    FileNameFromNS_Add(fileNameBuilder, "noNamespace");
                }
            }
 
            return fileNameBuilder.ToString();
        }
 
        private static void FileNameFromNS_Add(StringBuilder path, string segment)
        {
            if (segment != null)
            {
                char[] chars = segment.ToCharArray();
                for (int i = 0; i < chars.Length; i++)
                {
                    char c = chars[i];
                    if (Array.IndexOf(Path.GetInvalidFileNameChars(), c) == -1)
                    {
                        path.Append(c);
                    }
                }
            }
        }
 
        private static string GetFileNameWithExtension(string outputFile, string extension)
        {
            string outputFileWithExtension;
            if (!string.IsNullOrEmpty(extension) && (!Path.HasExtension(outputFile) || !Path.GetExtension(outputFile).Equals(extension, StringComparison.OrdinalIgnoreCase)))
            {
                outputFileWithExtension = outputFile + extension;
            }
            else
            {
                outputFileWithExtension = outputFile;
            }
            return outputFileWithExtension;
        }
 
        // Case insensitive search for Linux, macOS.
        public static bool FileExists(string filePath)
        {
            if (File.Exists(filePath))
            {
                return true;
            }
 
            var dirPath = Path.GetDirectoryName(filePath);
            if (Directory.Exists(dirPath))
            {
                var files = Directory.GetFiles(dirPath);
                return files.Any((f) => UriEqual(f, filePath));
            }
 
            return false;
        }
 
        public static bool TryCreateUri(string filePath1, out Uri fileUri)
        {
            if (Uri.TryCreate(filePath1, UriKind.Absolute, out fileUri) || Uri.TryCreate(filePath1, UriKind.Relative, out fileUri))
            {
                return fileUri.IsFile;
            }
            return false;
        }
 
 
        public static bool UriEqual(string filePath1, string filePath2)
        {
            Uri uri1, uri2;
            return Uri.TryCreate(filePath1, UriKind.Absolute, out uri1) && Uri.TryCreate(filePath2, UriKind.Absolute, out uri2) && StringComparer.OrdinalIgnoreCase.Compare(uri1.AbsoluteUri, uri2.AbsoluteUri) == 0 ||
                   Uri.TryCreate(filePath1, UriKind.Relative, out uri1) && Uri.TryCreate(filePath2, UriKind.Relative, out uri2) && StringComparer.OrdinalIgnoreCase.Compare(uri1.ToString(), uri2.ToString()) == 0;
        }
 
        public static string GetComposedUri(string baseUrl, string relUrl)
        {
            if (string.IsNullOrEmpty(baseUrl))
            {
                return relUrl;
            }
            if (string.IsNullOrEmpty(relUrl))
            {
                relUrl = string.Empty;
            }
            var baseUri = new Uri(baseUrl, UriKind.RelativeOrAbsolute);
            if (!baseUri.IsAbsoluteUri)
            {
                return relUrl;
            }
            return (new Uri(baseUri, relUrl)).GetComponents(UriComponents.AbsoluteUri, UriFormat.SafeUnescaped);
        }
 
        //Finds files that match a path (includes wildcards)
        public static FileInfo[] ResolveFiles(string path)
        {
            // Figure out the directory part
            string dirPath = Path.GetDirectoryName(path);
            if (string.IsNullOrEmpty(dirPath))
            {
                dirPath = Directory.GetCurrentDirectory();
            }
 
            DirectoryInfo dirInfo = new DirectoryInfo(dirPath);
 
            // Verify that the directory exists
            if (!dirInfo.Exists)
            {
                throw new DirectoryNotFoundException(string.Format(CultureInfo.CurrentCulture, MetadataResources.ErrDirectoryNotFoundFormat, dirInfo.FullName));
            }
 
            // Verify that the File exists
            string filename = Path.GetFileName(path);
            if (string.IsNullOrEmpty(filename))
            {
                throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, MetadataResources.ErrDirectoryInsteadOfFileFormat, path));
            }
 
            FileInfo[] fileInfoList = dirInfo.GetFiles(filename);
            if (fileInfoList.Length == 0)
            {
                throw new FileNotFoundException(string.Format(CultureInfo.CurrentCulture, MetadataResources.ErrNoFilesFoundFormat, path));
            }
 
            return fileInfoList;
        }
 
        public static bool TryResolveFiles(string path, out FileInfo[] fileInfoList)
        {
            fileInfoList = null;
            try
            {
                fileInfoList = ResolveFiles(path);
            }
            catch
            {
            }
            return fileInfoList != null;
        }
    }
}