예제 #1
0
        /// <summary>
        ///   Parse a sequence as UTF-8-encoded text representing a single JSON value into a JsonDocument.
        /// </summary>
        /// <remarks>
        ///   <para>
        ///     The <see cref="ReadOnlySequence{T}"/> may be used for the entire lifetime of the
        ///     JsonDocument object, and the caller must ensure that the data therein does not change during
        ///     the object lifetime.
        ///   </para>
        ///
        ///   <para>
        ///     Because the input is considered to be text, a UTF-8 Byte-Order-Mark (BOM) must not be present.
        ///   </para>
        /// </remarks>
        /// <param name="utf8Json">JSON text to parse.</param>
        /// <param name="options">Options to control the reader behavior during parsing.</param>
        /// <returns>
        ///   A JsonDocument representation of the JSON value.
        /// </returns>
        /// <exception cref="JsonException">
        ///   <paramref name="utf8Json"/> does not represent a valid single JSON value.
        /// </exception>
        /// <exception cref="ArgumentException">
        ///   <paramref name="options"/> contains unsupported options.
        /// </exception>
        public static JsonDocument Parse(ReadOnlySequence <byte> utf8Json, JsonDocumentOptions options = default)
        {
            JsonReaderOptions readerOptions = options.GetReaderOptions();

            if (utf8Json.IsSingleSegment)
            {
                return(Parse(utf8Json.First, readerOptions));
            }

            int length = checked ((int)utf8Json.Length);

            byte[] utf8Bytes = ArrayPool <byte> .Shared.Rent(length);

            try
            {
                utf8Json.CopyTo(utf8Bytes.AsSpan());
                return(Parse(utf8Bytes.AsMemory(0, length), readerOptions, utf8Bytes));
            }
            catch
            {
                // Holds document content, clear it before returning it.
                utf8Bytes.AsSpan(0, length).Clear();
                ArrayPool <byte> .Shared.Return(utf8Bytes);

                throw;
            }
        }
예제 #2
0
        internal static JsonDocument ParseValue(ReadOnlyMemory <char> json, JsonDocumentOptions options)
        {
            ReadOnlySpan <char> jsonChars = json.Span;
            int expectedByteCount         = JsonReaderHelper.GetUtf8ByteCount(jsonChars);

            byte[] owned;
            byte[] utf8Bytes = ArrayPool <byte> .Shared.Rent(expectedByteCount);

            try
            {
                int actualByteCount = JsonReaderHelper.GetUtf8FromText(jsonChars, utf8Bytes);
                Debug.Assert(expectedByteCount == actualByteCount);

                owned = new byte[actualByteCount];
                Buffer.BlockCopy(utf8Bytes, 0, owned, 0, actualByteCount);
            }
            finally
            {
                // Holds document content, clear it before returning it.
                utf8Bytes.AsSpan(0, expectedByteCount).Clear();
                ArrayPool <byte> .Shared.Return(utf8Bytes);
            }

            return(ParseUnrented(owned.AsMemory(), options.GetReaderOptions()));
        }
예제 #3
0
        /// <summary>
        ///   Parses text representing a single JSON value into a JsonDocument.
        /// </summary>
        /// <remarks>
        ///   The <see cref="ReadOnlyMemory{T}"/> value may be used for the entire lifetime of the
        ///   JsonDocument object, and the caller must ensure that the data therein does not change during
        ///   the object lifetime.
        /// </remarks>
        /// <param name="json">JSON text to parse.</param>
        /// <param name="options">Options to control the reader behavior during parsing.</param>
        /// <returns>
        ///   A JsonDocument representation of the JSON value.
        /// </returns>
        /// <exception cref="JsonException">
        ///   <paramref name="json"/> does not represent a valid single JSON value.
        /// </exception>
        /// <exception cref="ArgumentException">
        ///   <paramref name="options"/> contains unsupported options.
        /// </exception>
        public static JsonDocument Parse([StringSyntax(StringSyntaxAttribute.Json)] ReadOnlyMemory <char> json, JsonDocumentOptions options = default)
        {
            ReadOnlySpan <char> jsonChars = json.Span;
            int expectedByteCount         = JsonReaderHelper.GetUtf8ByteCount(jsonChars);

            byte[] utf8Bytes = ArrayPool <byte> .Shared.Rent(expectedByteCount);

            try
            {
                int actualByteCount = JsonReaderHelper.GetUtf8FromText(jsonChars, utf8Bytes);
                Debug.Assert(expectedByteCount == actualByteCount);

                return(Parse(
                           utf8Bytes.AsMemory(0, actualByteCount),
                           options.GetReaderOptions(),
                           utf8Bytes));
            }
            catch
            {
                // Holds document content, clear it before returning it.
                utf8Bytes.AsSpan(0, expectedByteCount).Clear();
                ArrayPool <byte> .Shared.Return(utf8Bytes);

                throw;
            }
        }
예제 #4
0
 internal static JsonDocument ParseRented(PooledByteBufferWriter utf8Json, JsonDocumentOptions options = default)
 {
     return(Parse(
                utf8Json.WrittenMemory,
                options.GetReaderOptions(),
                extraRentedArrayPoolBytes: null,
                extraPooledByteBufferWriter: utf8Json));
 }
예제 #5
0
        internal static JsonDocument ParseValue(ReadOnlySpan <byte> utf8Json, JsonDocumentOptions options)
        {
            Debug.Assert(utf8Json != null);

            byte[] owned = new byte[utf8Json.Length];
            utf8Json.CopyTo(owned);

            return(ParseUnrented(owned.AsMemory(), options.GetReaderOptions()));
        }
예제 #6
0
        internal static JsonDocument ParseValue(Stream utf8Json, JsonDocumentOptions options)
        {
            Debug.Assert(utf8Json != null);

            ArraySegment <byte> drained = ReadToEnd(utf8Json);

            Debug.Assert(drained.Array != null);

            byte[] owned = new byte[drained.Count];
            Buffer.BlockCopy(drained.Array, 0, owned, 0, drained.Count);

            // Holds document content, clear it before returning it.
            drained.AsSpan().Clear();
            ArrayPool <byte> .Shared.Return(drained.Array);

            return(ParseUnrented(owned.AsMemory(), options.GetReaderOptions()));
        }
예제 #7
0
        private static async Task <JsonDocument> ParseAsyncCore(
            Stream utf8Json,
            JsonDocumentOptions options         = default,
            CancellationToken cancellationToken = default)
        {
            ArraySegment <byte> drained = await ReadToEndAsync(utf8Json, cancellationToken).ConfigureAwait(false);

            try
            {
                return(Parse(drained.AsMemory(), options.GetReaderOptions(), drained.Array));
            }
            catch
            {
                // Holds document content, clear it before returning it.
                drained.AsSpan().Clear();
                ArrayPool <byte> .Shared.Return(drained.Array);

                throw;
            }
        }
예제 #8
0
        /// <summary>
        ///   Parse a <see cref="Stream"/> as UTF-8-encoded data representing a single JSON value into a
        ///   JsonDocument.  The Stream will be read to completion.
        /// </summary>
        /// <param name="utf8Json">JSON data to parse.</param>
        /// <param name="options">Options to control the reader behavior during parsing.</param>
        /// <returns>
        ///   A JsonDocument representation of the JSON value.
        /// </returns>
        /// <exception cref="JsonException">
        ///   <paramref name="utf8Json"/> does not represent a valid single JSON value.
        /// </exception>
        /// <exception cref="ArgumentException">
        ///   <paramref name="options"/> contains unsupported options.
        /// </exception>
        public static JsonDocument Parse(Stream utf8Json, JsonDocumentOptions options = default)
        {
            if (utf8Json == null)
            {
                throw new ArgumentNullException(nameof(utf8Json));
            }

            ArraySegment <byte> drained = ReadToEnd(utf8Json);

            try
            {
                return(Parse(drained.AsMemory(), options.GetReaderOptions(), drained.Array));
            }
            catch
            {
                // Holds document content, clear it before returning it.
                drained.AsSpan().Clear();
                ArrayPool <byte> .Shared.Return(drained.Array);

                throw;
            }
        }
예제 #9
0
 /// <summary>
 ///   Parse memory as UTF-8-encoded text representing a single JSON value into a JsonDocument.
 /// </summary>
 /// <remarks>
 ///   <para>
 ///     The <see cref="ReadOnlyMemory{T}"/> value will be used for the entire lifetime of the
 ///     JsonDocument object, and the caller must ensure that the data therein does not change during
 ///     the object lifetime.
 ///   </para>
 ///
 ///   <para>
 ///     Because the input is considered to be text, a UTF-8 Byte-Order-Mark (BOM) must not be present.
 ///   </para>
 /// </remarks>
 /// <param name="utf8Json">JSON text to parse.</param>
 /// <param name="options">Options to control the reader behavior during parsing.</param>
 /// <returns>
 ///   A JsonDocument representation of the JSON value.
 /// </returns>
 /// <exception cref="JsonException">
 ///   <paramref name="utf8Json"/> does not represent a valid single JSON value.
 /// </exception>
 /// <exception cref="ArgumentException">
 ///   <paramref name="options"/> contains unsupported options.
 /// </exception>
 public static JsonDocument Parse(ReadOnlyMemory <byte> utf8Json, JsonDocumentOptions options = default)
 {
     return(Parse(utf8Json, options.GetReaderOptions()));
 }
예제 #10
0
        /// <summary>
        ///   Parses a string representing JSON document into <see cref="JsonNode"/>.
        /// </summary>
        /// <param name="json">JSON to parse.</param>
        /// <param name="options">Options to control the reader behavior during parsing.</param>
        /// <param name="duplicatePropertyNameHandling">Specifies the way of handling duplicate property names.</param>
        /// <returns><see cref="JsonNode"/> representation of <paramref name="json"/>.</returns>
        public static JsonNode Parse(string json, JsonDocumentOptions options = default, DuplicatePropertyNameHandling duplicatePropertyNameHandling = DuplicatePropertyNameHandling.Replace)
        {
            Utf8JsonReader reader = new Utf8JsonReader(Encoding.UTF8.GetBytes(json), options.GetReaderOptions());

            var      currentNodes = new Stack <KeyValuePair <string, JsonNode> >(); // nodes currently being created
            JsonNode toReturn     = null;

            while (reader.Read())
            {
                JsonTokenType tokenType = reader.TokenType;
                KeyValuePair <string, JsonNode> currentPair = new KeyValuePair <string, JsonNode>();
                if (currentNodes.Any())
                {
                    currentPair = currentNodes.Peek();
                }

                void AddNewPair(JsonNode jsonNode, bool keepInCurrentNodes = false)
                {
                    KeyValuePair <string, JsonNode> newProperty;

                    if (currentPair.Value == null)
                    {
                        // If previous token was property name,
                        // it was added to stack with not null name and null value,
                        // otherwise, this is first JsonNode added
                        if (currentPair.Key != null)
                        {
                            // Create as property, keep name, replace null with new JsonNode:
                            currentNodes.Pop();
                            newProperty = new KeyValuePair <string, JsonNode>(currentPair.Key, jsonNode);
                        }
                        else
                        {
                            // Add first JsonNode:
                            newProperty = new KeyValuePair <string, JsonNode>(null, jsonNode);
                        }
                    }
                    else
                    {
                        // Create as value:
                        newProperty = new KeyValuePair <string, JsonNode>(null, jsonNode);
                    }

                    if (keepInCurrentNodes)
                    {
                        // If after adding property, it should be kept in currentNodes, it must be JsonObject or JsonArray
                        Debug.Assert(jsonNode.ValueKind == JsonValueKind.Object || jsonNode.ValueKind == JsonValueKind.Array);

                        currentNodes.Push(newProperty);
                    }
                    else
                    {
                        AddToParent(newProperty, ref currentNodes, ref toReturn, duplicatePropertyNameHandling);
                    }
                }

                switch (tokenType)
                {
                case JsonTokenType.StartObject:
                    AddNewPair(new JsonObject(), true);
                    break;

                case JsonTokenType.EndObject:
                    Debug.Assert(currentPair.Value is JsonObject);

                    currentNodes.Pop();
                    AddToParent(currentPair, ref currentNodes, ref toReturn, duplicatePropertyNameHandling);
                    break;

                case JsonTokenType.StartArray:
                    AddNewPair(new JsonArray(), true);
                    break;

                case JsonTokenType.EndArray:
                    Debug.Assert(currentPair.Value is JsonArray);

                    currentNodes.Pop();
                    AddToParent(currentPair, ref currentNodes, ref toReturn, duplicatePropertyNameHandling);
                    break;

                case JsonTokenType.PropertyName:
                    currentNodes.Push(new KeyValuePair <string, JsonNode>(reader.GetString(), null));
                    break;

                case JsonTokenType.Number:
                    AddNewPair(new JsonNumber(JsonHelpers.Utf8GetString(reader.ValueSpan)));
                    break;

                case JsonTokenType.String:
                    AddNewPair(new JsonString(reader.GetString()));
                    break;

                case JsonTokenType.True:
                    AddNewPair(new JsonBoolean(true));
                    break;

                case JsonTokenType.False:
                    AddNewPair(new JsonBoolean(false));
                    break;

                case JsonTokenType.Null:
                    AddNewPair(new JsonNull());
                    break;
                }
            }

            Debug.Assert(toReturn != null);
            return(toReturn);
        }