File: NupkgMetadata\NupkgMetadataFileFormat.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.Globalization;
using System.IO;
using System.Text.Json;
using System.Text.Json.Serialization;
using NuGet.Common;
using NuGet.Packaging.NupkgMetadata;

namespace NuGet.Packaging
{
    public static class NupkgMetadataFileFormat
    {
        public static readonly int Version = 2;

        private static readonly JsonSerializerOptions JsonSerializerOptions = new JsonSerializerOptions()
        {
            WriteIndented = true,
            PropertyNameCaseInsensitive = true,
            PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
            // This file is not intended to be parsed in javascript, and the contentHash property contains a Base64 encoded string that
            // can contain characters such as + that has not been encoded in the past.
            Encoder = System.Text.Encodings.Web.JavaScriptEncoder.UnsafeRelaxedJsonEscaping,
            DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
        };

        private static readonly NupkgMetadataSerializationContext JsonContext = new NupkgMetadataSerializationContext(JsonSerializerOptions);

        public static NupkgMetadataFile Read(string filePath)
        {
            return Read(filePath, NullLogger.Instance);
        }

        public static NupkgMetadataFile Read(string filePath, ILogger log)
        {
            return FileUtility.SafeRead(filePath, (stream, nupkgMetadataFilePath) => Read(stream, log, nupkgMetadataFilePath));
        }

        public static NupkgMetadataFile Read(Stream stream, ILogger log, string path)
        {
            if (stream is null) { throw new ArgumentNullException(nameof(stream)); }

            try
            {
                NupkgMetadataFile? nupkgMetadata = JsonSerializer.Deserialize<NupkgMetadataFile>(stream, JsonContext.NupkgMetadataFile);
                if (nupkgMetadata == null)
                {
                    throw new InvalidDataException();
                }
                return nupkgMetadata;
            }
            catch (JsonException ex)
            {
                throw LogAndWrap(log, path, ex);
            }
            catch (Exception ex)
            {
                throw LogAndWrap(log, path, ex);
            }

            static InvalidDataException LogAndWrap(ILogger log, string path, Exception ex)
            {
                string message = (string.Format(CultureInfo.CurrentCulture,
                    Strings.Error_LoadingHashFile,
                    path, ex.Message));
                log.LogWarning(message);
                return new InvalidDataException(message, ex);
            }
        }

        public static void Write(string filePath, NupkgMetadataFile hashFile)
        {
            // Create the directory if it does not exist
            var fileInfo = new FileInfo(filePath);
            fileInfo.Directory!.Create();

            using (var stream = new FileStream(filePath, FileMode.Create, FileAccess.Write, FileShare.None))
            {
                Write(stream, hashFile);
            }
        }

        public static void Write(Stream stream, NupkgMetadataFile hashFile)
        {
            if (stream is null) { throw new ArgumentNullException(nameof(stream)); }

            JsonSerializer.Serialize(stream, hashFile, JsonContext.NupkgMetadataFile);
        }
    }
}