// 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.Globalization; using System.IO; using System.Linq; using Microsoft.VisualStudio.SecretManager; using Newtonsoft.Json; using Newtonsoft.Json.Linq; namespace Microsoft.Extensions.Configuration.Json { internal class JsonConfigurationFileParser { private JsonConfigurationFileParser() { } private readonly IDictionary _data = new SortedDictionary(StringComparer.OrdinalIgnoreCase); private readonly Stack _context = new Stack(); private string _currentPath; private JsonTextReader _reader; public static IDictionary Parse(Stream input) => new JsonConfigurationFileParser().ParseStream(input); private IDictionary ParseStream(Stream input) { _data.Clear(); _reader = new JsonTextReader(new StreamReader(input)); _reader.DateParseHandling = DateParseHandling.None; var jsonConfig = JObject.Load(_reader); VisitJObject(jsonConfig); return _data; } private void VisitJObject(JObject jObject) { foreach (var property in jObject.Properties()) { EnterContext(property.Name); VisitProperty(property); ExitContext(); } } private void VisitProperty(JProperty property) { VisitToken(property.Value); } private void VisitToken(JToken token) { switch (token.Type) { case JTokenType.Object: VisitJObject(token.Value()); break; case JTokenType.Array: VisitArray(token.Value()); break; case JTokenType.Integer: case JTokenType.Float: case JTokenType.String: case JTokenType.Boolean: case JTokenType.Bytes: case JTokenType.Raw: case JTokenType.Null: VisitPrimitive(token.Value()); break; default: throw new FormatException(Resources.FormatError_UnsupportedJSONToken( _reader.TokenType, _reader.Path, _reader.LineNumber, _reader.LinePosition)); } } private void VisitArray(JArray array) { for (int index = 0; index < array.Count; index++) { EnterContext(index.ToString()); VisitToken(array[index]); ExitContext(); } } private void VisitPrimitive(JValue data) { var key = _currentPath; if (_data.ContainsKey(key)) { throw new FormatException(Resources.FormatError_KeyIsDuplicated(key)); } _data[key] = data.ToString(CultureInfo.InvariantCulture); } private void EnterContext(string context) { _context.Push(context); _currentPath = ConfigurationPath.Combine(_context.Reverse()); } private void ExitContext() { _context.Pop(); _currentPath = ConfigurationPath.Combine(_context.Reverse()); } } }