/// <inheritdoc />
            public override IEnumerable <ObjectProperty> GetObjectProperties(IJsonNavigatorNode objectNode)
            {
                ReadOnlyMemory <byte> buffer = JsonBinaryNavigator.GetNodeOfType(
                    JsonNodeType.Object,
                    objectNode);

                byte typeMarker       = buffer.Span[0];
                int  firstValueOffset = JsonBinaryEncoding.GetFirstValueOffset(typeMarker);

                buffer = buffer.Slice(firstValueOffset);
                while (buffer.Length != 0)
                {
                    int nameNodeLength = JsonBinaryEncoding.GetValueLength(buffer.Span);
                    if (nameNodeLength > buffer.Length)
                    {
                        throw new JsonInvalidTokenException();
                    }
                    ReadOnlyMemory <byte> nameNode = buffer.Slice(0, nameNodeLength);
                    buffer = buffer.Slice(nameNodeLength);

                    int valueNodeLength = JsonBinaryEncoding.GetValueLength(buffer.Span);
                    if (valueNodeLength > buffer.Length)
                    {
                        throw new JsonInvalidTokenException();
                    }
                    ReadOnlyMemory <byte> valueNode = buffer.Slice(0, valueNodeLength);
                    buffer = buffer.Slice(valueNodeLength);

                    yield return(new ObjectProperty(
                                     new BinaryNavigatorNode(nameNode, JsonNodeType.FieldName),
                                     new BinaryNavigatorNode(valueNode, NodeTypes.GetNodeType(valueNode.Span[0]))));
                }
            }
Exemple #2
0
            private IEnumerable <BinaryNavigatorNode> GetArrayItemsInternal(ReadOnlyMemory <byte> buffer)
            {
                byte typeMarker = buffer.Span[0];

                int firstArrayItemOffset = JsonBinaryEncoding.GetFirstValueOffset(typeMarker);
                int arrayLength          = JsonBinaryEncoding.GetValueLength(buffer.Span);

                // Scope to just the array
                buffer = buffer.Slice(0, (int)arrayLength);

                // Seek to the first array item
                buffer = buffer.Slice(firstArrayItemOffset);

                while (buffer.Length != 0)
                {
                    int arrayItemLength = JsonBinaryEncoding.GetValueLength(buffer.Span);
                    if (arrayItemLength > buffer.Length)
                    {
                        // Array Item got cut off.
                        throw new JsonInvalidTokenException();
                    }

                    // Create a buffer for that array item
                    BinaryNavigatorNode arrayItem = new BinaryNavigatorNode(
                        buffer.Slice(0, arrayItemLength),
                        NodeTypes.GetNodeType(buffer.Span[0]));
                    yield return(arrayItem);

                    // Slice off the array item
                    buffer = buffer.Slice(arrayItemLength);
                }
            }
            public static IEnumerable <ObjectProperty> GetObjectProperties(ReadOnlyMemory <byte> buffer)
            {
                byte typeMarker = buffer.Span[0];

                if (!JsonBinaryEncoding.TypeMarker.IsObject(typeMarker))
                {
                    throw new JsonInvalidTokenException();
                }

                int firstValueOffset = JsonBinaryEncoding.GetFirstValueOffset(typeMarker);

                buffer = buffer.Slice(firstValueOffset);
                while (buffer.Length != 0)
                {
                    int nameNodeLength = JsonBinaryEncoding.GetValueLength(buffer.Span);
                    if (nameNodeLength > buffer.Length)
                    {
                        throw new JsonInvalidTokenException();
                    }
                    ReadOnlyMemory <byte> name = buffer.Slice(0, nameNodeLength);
                    buffer = buffer.Slice(nameNodeLength);

                    int valueNodeLength = JsonBinaryEncoding.GetValueLength(buffer.Span);
                    if (valueNodeLength > buffer.Length)
                    {
                        throw new JsonInvalidTokenException();
                    }
                    ReadOnlyMemory <byte> value = buffer.Slice(0, valueNodeLength);
                    buffer = buffer.Slice(valueNodeLength);

                    yield return(new ObjectProperty(name, value));
                }
            }
            private bool TryGetValueAt(long offset, long length, long index, out BinaryNode node)
            {
                long currentOffset = offset;

                for (long count = 0; count < index; count++)
                {
                    long valueLength = JsonBinaryEncoding.GetValueLength(this.buffer, currentOffset);
                    if (valueLength == 0)
                    {
                        node = default(BinaryNode);
                        return(false);
                    }

                    currentOffset += valueLength;
                    if (currentOffset >= (offset + length))
                    {
                        node = default(BinaryNode);
                        return(false);
                    }
                }

                if (currentOffset > int.MaxValue)
                {
                    throw new InvalidOperationException($"{nameof(currentOffset)} is greater than int.MaxValue");
                }

                node = this.CreateBinaryNode((int)currentOffset);
                return(true);
            }
Exemple #5
0
            public JsonBinaryReader(
                ReadOnlyMemory <byte> buffer,
                IReadOnlyJsonStringDictionary jsonStringDictionary = null)
            {
                if (buffer.Length < 2)
                {
                    throw new ArgumentException($"{nameof(buffer)} must have at least two byte.");
                }

                if (buffer.Span[0] != (byte)JsonSerializationFormat.Binary)
                {
                    throw new ArgumentNullException("buffer must be binary encoded.");
                }

                // offset for the 0x80 (128) binary serialization type marker.
                buffer = buffer.Slice(1);

                // Only navigate the outer most json value and trim off trailing bytes
                int jsonValueLength = JsonBinaryEncoding.GetValueLength(buffer.Span);

                if (buffer.Length < jsonValueLength)
                {
                    throw new ArgumentException("buffer is shorter than the length prefix.");
                }

                buffer = buffer.Slice(0, jsonValueLength);

                this.jsonBinaryBuffer       = new JsonBinaryMemoryReader(buffer);
                this.arrayAndObjectEndStack = new Stack <int>();
                this.jsonStringDictionary   = jsonStringDictionary;
            }
            /// <summary>
            /// Gets an IEnumerable of <see cref="IJsonNavigatorNode"/> properties from an object node.
            /// </summary>
            /// <param name="objectNavigatorNode">The <see cref="IJsonNavigatorNode"/> of object node to get the properties from.</param>
            /// <returns>The IEnumerable of <see cref="IJsonNavigatorNode"/> properties from an object node.</returns>
            public override IEnumerable <ObjectProperty> GetObjectProperties(IJsonNavigatorNode objectNavigatorNode)
            {
                if (objectNavigatorNode == null)
                {
                    throw new ArgumentNullException(nameof(objectNavigatorNode));
                }

                if (!(((objectNavigatorNode as BinaryNode)?.JsonNodeType ?? JsonNodeType.Unknown) == JsonNodeType.Object))
                {
                    throw new ArgumentException($"{nameof(objectNavigatorNode)} must actually be a binary object node.");
                }

                int  offset           = ((BinaryNode)objectNavigatorNode).Offset;
                byte typeMarker       = this.buffer[offset];
                long objectLength     = JsonBinaryEncoding.GetValueLength(this.buffer, offset);
                long firstValueOffset = offset + JsonBinaryEncoding.GetFirstValueOffset(typeMarker);
                long bytesToProcess   = (offset + objectLength) - firstValueOffset;

                for (int bytesProcessed = 0; bytesProcessed < bytesToProcess;)
                {
                    BinaryNode nameNode = new BinaryNode((int)(firstValueOffset + bytesProcessed), JsonNodeType.FieldName);
                    bytesProcessed += (int)JsonBinaryEncoding.GetValueLength(this.buffer, firstValueOffset + bytesProcessed);
                    BinaryNode valueNode = this.CreateBinaryNode((int)(firstValueOffset + bytesProcessed));
                    bytesProcessed += (int)JsonBinaryEncoding.GetValueLength(this.buffer, firstValueOffset + bytesProcessed);
                    yield return(new ObjectProperty(nameNode, valueNode));
                }
            }
            /// <summary>
            /// Gets the node at a particular index of an array node
            /// </summary>
            /// <param name="arrayNavigatorNode">The <see cref="IJsonNavigatorNode"/> of the (array) node to index from.</param>
            /// <param name="index">The offset into the array</param>
            /// <returns>The <see cref="IJsonNavigatorNode"/> of the node at a particular index of an array node</returns>
            public override IJsonNavigatorNode GetArrayItemAt(IJsonNavigatorNode arrayNavigatorNode, int index)
            {
                if (arrayNavigatorNode == null)
                {
                    throw new ArgumentNullException(nameof(arrayNavigatorNode));
                }

                if (!(((arrayNavigatorNode as BinaryNode)?.JsonNodeType ?? JsonNodeType.Unknown) == JsonNodeType.Array))
                {
                    throw new ArgumentException($"{nameof(arrayNavigatorNode)} must be a binary array node.");
                }

                // TODO (brchon): We can optimize for the case where the count is serialized so we can avoid using the linear time call to TryGetValueAt().

                int  arrayOffset = ((BinaryNode)arrayNavigatorNode).Offset;
                byte typeMarker  = this.buffer[arrayOffset];

                BinaryNode node;
                long       firstArrayItemOffset = arrayOffset + JsonBinaryEncoding.GetFirstValueOffset(typeMarker);
                long       arrayLength          = JsonBinaryEncoding.GetValueLength(this.buffer, arrayOffset);
                long       arrayItemsLength     = arrayLength - (firstArrayItemOffset - arrayOffset);

                if (!this.TryGetValueAt(firstArrayItemOffset, arrayItemsLength, index, out node))
                {
                    throw new IndexOutOfRangeException($"Tried to access index:{index} in an array.");
                }

                return(node);
            }
            /// <summary>
            /// Initializes a new instance of the JsonBinaryNavigator class
            /// </summary>
            /// <param name="buffer">The (UTF-8) buffer to navigate.</param>
            /// <param name="jsonStringDictionary">The JSON string dictionary.</param>
            /// <param name="skipValidation">whether to skip validation or not.</param>
            public JsonBinaryNavigator(
                ReadOnlyMemory <byte> buffer,
                JsonStringDictionary jsonStringDictionary,
                bool skipValidation = false)
            {
                if (buffer.Length < 2)
                {
                    throw new ArgumentException($"{nameof(buffer)} must have at least two byte.");
                }

                if (buffer.Span[0] != (byte)JsonSerializationFormat.Binary)
                {
                    throw new ArgumentNullException("buffer must be binary encoded.");
                }

                // offset for the 0x80 (128) binary serialization type marker.
                buffer = buffer.Slice(1);

                // Only navigate the outer most json value and trim off trailing bytes
                int jsonValueLength = JsonBinaryEncoding.GetValueLength(buffer.Span);

                if (buffer.Length < jsonValueLength)
                {
                    throw new ArgumentException("buffer is shorter than the length prefix.");
                }

                buffer = buffer.Slice(0, jsonValueLength);

                this.buffer = buffer;
                this.jsonStringDictionary = jsonStringDictionary;
                this.rootNode             = new BinaryNavigatorNode(this.buffer, NodeTypes.GetNodeType(this.buffer.Span[0]));
            }
            public static IEnumerable <ReadOnlyMemory <byte> > GetArrayItems(ReadOnlyMemory <byte> buffer)
            {
                byte typeMarker = buffer.Span[0];

                if (!JsonBinaryEncoding.TypeMarker.IsArray(typeMarker))
                {
                    throw new JsonInvalidTokenException();
                }

                int firstArrayItemOffset = JsonBinaryEncoding.GetFirstValueOffset(typeMarker);
                int arrayLength          = JsonBinaryEncoding.GetValueLength(buffer.Span);

                // Scope to just the array
                buffer = buffer.Slice(0, arrayLength);

                // Seek to the first array item
                buffer = buffer.Slice(firstArrayItemOffset);

                while (buffer.Length != 0)
                {
                    int arrayItemLength = JsonBinaryEncoding.GetValueLength(buffer.Span);
                    if (arrayItemLength > buffer.Length)
                    {
                        // Array Item got cut off.
                        throw new JsonInvalidTokenException();
                    }

                    // Create a buffer for that array item
                    ReadOnlyMemory <byte> arrayItem = buffer.Slice(0, arrayItemLength);
                    yield return(arrayItem);

                    // Slice off the array item
                    buffer = buffer.Slice(arrayItemLength);
                }
            }
            private int GetValueCount(long offset, long length)
            {
                long bytesProcessed = 0;
                int  count          = 0;

                while (bytesProcessed < length)
                {
                    count++;
                    bytesProcessed += JsonBinaryEncoding.GetValueLength(this.buffer, offset + bytesProcessed);
                }

                return(count);
            }
            private static int GetValueCount(ReadOnlySpan <byte> node)
            {
                int count = 0;

                while (!node.IsEmpty)
                {
                    count++;
                    int nodeLength = JsonBinaryEncoding.GetValueLength(node);
                    node = node.Slice(nodeLength);
                }

                return(count);
            }
            /// <summary>
            /// Tries to get the buffered raw json
            /// </summary>
            /// <param name="jsonNode">The json node of interest</param>
            /// <param name="bufferedRawJson">The raw json.</param>
            /// <returns>True if bufferedRawJson was set. False otherwise.</returns>
            public override bool TryGetBufferedRawJson(
                IJsonNavigatorNode jsonNode,
                out IReadOnlyList <byte> bufferedRawJson)
            {
                if (jsonNode == null || !(jsonNode is BinaryNode jsonBinaryNode))
                {
                    bufferedRawJson = default(IReadOnlyList <byte>);
                    return(false);
                }

                int nodeLength = (int)JsonBinaryEncoding.GetValueLength(this.buffer, (long)jsonBinaryNode.Offset);

                bufferedRawJson = new ArraySegment <byte>(this.buffer, jsonBinaryNode.Offset, nodeLength);

                return(true);
            }
            public JsonBinaryReader(
                ReadOnlyMemory<byte> buffer,
                IReadOnlyJsonStringDictionary jsonStringDictionary = null)
            {
                if (buffer.IsEmpty)
                {
                    throw new ArgumentException($"{nameof(buffer)} must not be empty.");
                }

                // Only navigate the outer most json value and trim off trailing bytes
                int jsonValueLength = JsonBinaryEncoding.GetValueLength(buffer.Span);
                if (buffer.Length < jsonValueLength)
                {
                    throw new ArgumentException("buffer is shorter than the length prefix.");
                }

                buffer = buffer.Slice(0, jsonValueLength);

                this.jsonBinaryBuffer = new JsonBinaryMemoryReader(buffer);
                this.arrayAndObjectEndStack = new Stack<int>();
                this.jsonStringDictionary = jsonStringDictionary;
            }
            internal JsonBinaryReader(
                ReadOnlyMemory <byte> rootBuffer,
                int?indexToStartFrom = null,
                IReadOnlyJsonStringDictionary jsonStringDictionary = null)
            {
                if (rootBuffer.IsEmpty)
                {
                    throw new ArgumentException($"{nameof(rootBuffer)} must not be empty.");
                }

                this.rootBuffer = rootBuffer;

                ReadOnlyMemory <byte> readerBuffer = this.rootBuffer;

                if (indexToStartFrom.HasValue)
                {
                    readerBuffer = readerBuffer.Slice(start: indexToStartFrom.Value);
                }
                else
                {
                    // Skip the 0x80
                    readerBuffer = readerBuffer.Slice(start: 1);
                }

                // Only navigate the outer most json value and trim off trailing bytes
                int jsonValueLength = JsonBinaryEncoding.GetValueLength(readerBuffer.Span);

                if (readerBuffer.Length < jsonValueLength)
                {
                    throw new ArgumentException("buffer is shorter than the length prefix.");
                }

                readerBuffer = readerBuffer.Slice(0, jsonValueLength);

                // offset for the 0x80 binary type marker
                this.jsonBinaryBuffer       = new JsonBinaryMemoryReader(readerBuffer);
                this.arrayAndObjectEndStack = new Stack <int>();
                this.jsonStringDictionary   = jsonStringDictionary;
            }
            private static bool TryGetValueAt(
                ReadOnlyMemory <byte> arrayNode,
                long index,
                out ReadOnlyMemory <byte> arrayItem)
            {
                ReadOnlyMemory <byte> buffer = arrayNode;
                byte typeMarker = buffer.Span[0];

                int firstArrayItemOffset = JsonBinaryEncoding.GetFirstValueOffset(typeMarker);
                int arrayLength          = JsonBinaryEncoding.GetValueLength(buffer.Span);

                // Scope to just the array
                buffer = buffer.Slice(0, (int)arrayLength);

                // Seek to the first array item
                buffer = buffer.Slice(firstArrayItemOffset);

                for (long count = 0; count < index; count++)
                {
                    // Skip over the array item.
                    int arrayItemLength = JsonBinaryEncoding.GetValueLength(buffer.Span);
                    if (arrayItemLength >= buffer.Length)
                    {
                        arrayItem = default;
                        return(false);
                    }

                    buffer = buffer.Slice(arrayItemLength);
                }

                // Scope to just that array item
                int itemLength = JsonBinaryEncoding.GetValueLength(buffer.Span);

                buffer = buffer.Slice(0, itemLength);

                arrayItem = buffer;
                return(true);
            }
            /// <summary>
            /// Gets an IEnumerable of <see cref="IJsonNavigatorNode"/>s for an arrayNode.
            /// </summary>
            /// <param name="arrayNavigatorNode">The <see cref="IJsonNavigatorNode"/> of the array to get the items from</param>
            /// <returns>The IEnumerable of <see cref="IJsonNavigatorNode"/>s for an arrayNode.</returns>
            public override IEnumerable <IJsonNavigatorNode> GetArrayItems(IJsonNavigatorNode arrayNavigatorNode)
            {
                if (arrayNavigatorNode == null)
                {
                    throw new ArgumentNullException(nameof(arrayNavigatorNode));
                }

                if (!(((arrayNavigatorNode as BinaryNode)?.JsonNodeType ?? JsonNodeType.Unknown) == JsonNodeType.Array))
                {
                    throw new ArgumentException($"{nameof(arrayNavigatorNode)} must be a binary array node.");
                }

                int  arrayOffset = ((BinaryNode)arrayNavigatorNode).Offset;
                byte typeMarker  = this.buffer[arrayOffset];

                long arrayLength      = JsonBinaryEncoding.GetValueLength(this.buffer, arrayOffset);
                long firstValueOffset = arrayOffset + JsonBinaryEncoding.GetFirstValueOffset(typeMarker);
                long bytesToProcess   = (arrayOffset + arrayLength) - firstValueOffset;

                for (int bytesProcessed = 0; bytesProcessed < bytesToProcess; bytesProcessed += (int)JsonBinaryEncoding.GetValueLength(this.buffer, firstValueOffset + bytesProcessed))
                {
                    yield return(this.CreateBinaryNode((int)(firstValueOffset + bytesProcessed)));
                }
            }
Exemple #17
0
            /// <inheritdoc />
            public override bool Read()
            {
                // Check if we just finished an array or object context
                if (!this.arrayAndObjectEndStack.Empty() && this.arrayAndObjectEndStack.Peek() == this.jsonBinaryBuffer.Position)
                {
                    if (this.JsonObjectState.InArrayContext)
                    {
                        this.JsonObjectState.RegisterEndArray();
                    }
                    else if (this.JsonObjectState.InObjectContext)
                    {
                        this.JsonObjectState.RegisterEndObject();
                    }
                    else
                    {
                        throw new JsonInvalidTokenException();
                    }

                    this.currentTokenPosition = this.jsonBinaryBuffer.Position;
                    this.arrayAndObjectEndStack.Pop();
                }
                else if (this.jsonBinaryBuffer.IsEof)
                {
                    // Need to check if we are still inside of an object or array
                    if (this.JsonObjectState.CurrentDepth != 0)
                    {
                        if (this.JsonObjectState.InObjectContext)
                        {
                            throw new JsonMissingEndObjectException();
                        }

                        if (this.JsonObjectState.InArrayContext)
                        {
                            throw new JsonMissingEndArrayException();
                        }

                        throw new InvalidOperationException("Expected to be in either array or object context");
                    }

                    return(false);
                }
                else if (this.JsonObjectState.CurrentDepth == 0 && this.CurrentTokenType != JsonTokenType.NotStarted)
                {
                    // There are trailing characters outside of the outter most object or array
                    throw new JsonUnexpectedTokenException();
                }
                else
                {
                    ReadOnlySpan <byte> readOnlySpan = this.jsonBinaryBuffer.GetBufferedRawJsonToken().Span;
                    int nextTokenOffset = JsonBinaryEncoding.GetValueLength(readOnlySpan);

                    byte          typeMarker    = readOnlySpan[0];
                    JsonTokenType jsonTokenType = JsonBinaryReader.GetJsonTokenType(typeMarker);
                    switch (jsonTokenType)
                    {
                    case JsonTokenType.String when this.JsonObjectState.IsPropertyExpected:
                        jsonTokenType = JsonTokenType.FieldName;
                        break;

                    // If this is begin array/object token then we need to identify where array/object end token is.
                    // Also the next token offset is just the array type marker + length prefix + count prefix
                    case JsonTokenType.BeginArray:
                    case JsonTokenType.BeginObject:
                        this.arrayAndObjectEndStack.Push(this.jsonBinaryBuffer.Position + nextTokenOffset);
                        nextTokenOffset = JsonBinaryReader.GetArrayOrObjectPrefixLength(typeMarker);
                        break;
                    }

                    this.JsonObjectState.RegisterToken(jsonTokenType);
                    this.currentTokenPosition = this.jsonBinaryBuffer.Position;
                    this.jsonBinaryBuffer.SkipBytes(nextTokenOffset);
                }

                return(true);
            }
 public static bool TryGetValueLength(ReadOnlySpan <byte> buffer, out int length)
 {
     // Too lazy to convert this right now.
     length = (int)JsonBinaryEncoding.GetValueLength(buffer);
     return(true);
 }