/* ======================================================================== * Copyright (c) 2005-2025 The OPC Foundation, Inc. All rights reserved. * * OPC Foundation MIT License 1.00 * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. * * The complete license agreement can be found here: * http://opcfoundation.org/License/MIT/1.00/ * ======================================================================*/ using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Text; namespace Opc.Ua.SourceGeneration { /// /// Generator file system that reads from additional texts /// internal sealed class SourceGeneratorFileSystem : IFileSystem { /// /// Create generator file system /// public SourceGeneratorFileSystem( IEnumerable additionalTexts) { // A project can list the same file as an AdditionalFile more than // once (globs overlapping an explicit item, for instance). Keep the // first entry rather than letting ToDictionary throw out of the // generator's constructor, which happens before any guarded region // and surfaces as a bare generator crash. m_files = []; foreach (AdditionalText text in additionalTexts) { if (text?.Path != null && !m_files.ContainsKey(text.Path)) { m_files.Add(text.Path, text); } } } /// public void Delete(string path, bool isDirectory = false) { if (!isDirectory) { m_files.Remove(path); } } /// public bool Exists(string path, bool isDirectory = false) { if (isDirectory) { return false; } return m_files.ContainsKey(path); } /// public DateTime GetLastWriteTime(string path) { return DateTime.MinValue; } /// public long GetLength(string path) { if (m_files.TryGetValue(path, out AdditionalText text)) { SourceText sourceText = text.GetText(); if (sourceText != null) { return sourceText.Length; } } throw new FileNotFoundException($"File not found: {path}"); } /// public Stream OpenRead(string path) { if (m_files.TryGetValue(path, out AdditionalText text)) { SourceText sourceText = text.GetText(); if (sourceText != null) { var memoryStream = new MemoryStream(); using (var writer = new StreamWriter( memoryStream, Encoding.UTF8, 8 * 1024, true)) { sourceText.Write(writer); } memoryStream.Position = 0; return memoryStream; } } throw new FileNotFoundException($"File not found: {path}"); } /// public void Replace(string sourcePath, string destinationPath) { throw new NotSupportedException("Write not allowed"); } /// public Stream OpenWrite(string path) { throw new NotSupportedException("Write not allowed"); } private readonly Dictionary m_files; } }