/// <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; } }
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())); }
/// <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; } }
internal static JsonDocument ParseRented(PooledByteBufferWriter utf8Json, JsonDocumentOptions options = default) { return(Parse( utf8Json.WrittenMemory, options.GetReaderOptions(), extraRentedArrayPoolBytes: null, extraPooledByteBufferWriter: utf8Json)); }
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())); }
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())); }
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; } }
/// <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; } }
/// <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())); }
/// <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); }