/// <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])))); } }
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); }
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))); } }
/// <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); }