Example #1
0
            /// <inheritdoc />
            public override IEnumerable <IJsonNavigatorNode> GetArrayItems(IJsonNavigatorNode arrayNode)
            {
                ReadOnlyMemory <byte> buffer = JsonBinaryNavigator.GetNodeOfType(
                    JsonNodeType.Array,
                    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);

                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
                    IJsonNavigatorNode arrayItem = new BinaryNavigatorNode(
                        buffer.Slice(0, arrayItemLength),
                        NodeTypes.GetNodeType(buffer.Span[0]));
                    yield return(arrayItem);

                    // Slice off the array item
                    buffer = buffer.Slice(arrayItemLength);
                }
            }
            /// <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)));
                }
            }
Example #3
0
 public static bool TryGetFloat64Value(
     ReadOnlySpan <byte> float64Token,
     out double float64Value) => JsonBinaryEncoding.TryGetFixedWidthValue <double>(
     float64Token,
     JsonBinaryEncoding.TypeMarker.Float64,
     out float64Value);
Example #4
0
 public static bool TryGetFloat32Value(
     ReadOnlySpan <byte> float32Token,
     out float float32Value) => JsonBinaryEncoding.TryGetFixedWidthValue <float>(
     float32Token,
     JsonBinaryEncoding.TypeMarker.Float32,
     out float32Value);
Example #5
0
 public static bool TryGetUInt32Value(
     ReadOnlySpan <byte> uInt32Token,
     out uint uInt32Value) => JsonBinaryEncoding.TryGetFixedWidthValue <uint>(
     uInt32Token,
     JsonBinaryEncoding.TypeMarker.UInt32,
     out uInt32Value);
Example #6
0
 public static bool TryGetInt64Value(
     ReadOnlySpan <byte> int64Token,
     out long int64Value) => JsonBinaryEncoding.TryGetFixedWidthValue <long>(
     int64Token,
     JsonBinaryEncoding.TypeMarker.Int64,
     out int64Value);
Example #7
0
            private void ForceRewriteRawJsonValue(
                ReadOnlyMemory <byte> rawJsonValue,
                bool isFieldName,
                IReadOnlyJsonStringDictionary jsonStringDictionary)
            {
                byte typeMarker = rawJsonValue.Span[0];

                if (!JsonBinaryEncoding.TypeMarker.IsSystemString(typeMarker) &&
                    !JsonBinaryEncoding.TypeMarker.IsEmptyArray(typeMarker) &&
                    !JsonBinaryEncoding.TypeMarker.IsEmptyObject(typeMarker))
                {
                    JsonNodeType nodeType = JsonBinaryEncoding.NodeTypes.GetNodeType(typeMarker);
                    switch (nodeType)
                    {
                    case JsonNodeType.String:
                    {
                        if (!JsonBinaryEncoding.TryGetBufferedStringValue(
                                Utf8Memory.UnsafeCreateNoValidation(rawJsonValue),
                                jsonStringDictionary,
                                out Utf8Memory bufferedStringValue))
                        {
                            throw new InvalidOperationException("Excepted to get the buffered string value.");
                        }

                        if (isFieldName)
                        {
                            this.WriteFieldName(bufferedStringValue.Span);
                        }
                        else
                        {
                            this.WriteStringValue(bufferedStringValue.Span);
                        }

                        return;
                    }

                    case JsonNodeType.Array:
                    {
                        this.WriteArrayStart();

                        foreach (ReadOnlyMemory <byte> arrayItem in JsonBinaryEncoding.Enumerator.GetArrayItems(rawJsonValue))
                        {
                            this.ForceRewriteRawJsonValue(arrayItem, isFieldName, jsonStringDictionary);
                        }

                        this.WriteArrayEnd();

                        return;
                    }

                    case JsonNodeType.Object:
                    {
                        this.WriteObjectStart();

                        foreach (JsonBinaryEncoding.Enumerator.ObjectProperty property in JsonBinaryEncoding.Enumerator.GetObjectProperties(rawJsonValue))
                        {
                            this.ForceRewriteRawJsonValue(property.Name, isFieldName: true, jsonStringDictionary);
                            this.ForceRewriteRawJsonValue(property.Value, isFieldName: false, jsonStringDictionary);
                        }

                        this.WriteObjectEnd();

                        return;
                    }
                    }
                }

                // Other that whether or not this is a field name, the type of the value does not matter here
                this.JsonObjectState.RegisterToken(isFieldName ? JsonTokenType.FieldName : JsonTokenType.String);
                this.binaryWriter.Write(rawJsonValue.Span);
                if (!isFieldName)
                {
                    this.bufferedContexts.Peek().Count++;
                }
            }
            /// <inheritdoc />
            public override bool Read()
            {
                JsonTokenType jsonTokenType;
                int nextTokenOffset;
                // First check if we just finished an array or object context
                if (!this.arrayAndObjectEndStack.Empty() && (this.arrayAndObjectEndStack.Peek() == this.jsonBinaryBuffer.Position))
                {
                    if (this.JsonObjectState.InArrayContext)
                    {
                        jsonTokenType = JsonTokenType.EndArray;
                    }
                    else if (this.JsonObjectState.InObjectContext)
                    {
                        jsonTokenType = JsonTokenType.EndObject;
                    }
                    else
                    {
                        throw new JsonInvalidTokenException();
                    }

                    nextTokenOffset = 0;
                    this.arrayAndObjectEndStack.Pop();
                }
                else
                {
                    // We are not at the end of a context.
                    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();
                            }
                            else if (this.JsonObjectState.InArrayContext)
                            {
                                throw new JsonMissingEndArrayException();
                            }
                            else
                            {
                                throw new InvalidOperationException("Expected to be in either array or object context");
                            }
                        }

                        return false;
                    }

                    if ((this.JsonObjectState.CurrentDepth == 0) && (this.CurrentTokenType != JsonTokenType.NotStarted))
                    {
                        // There are trailing characters outside of the outter most object or array
                        throw new JsonUnexpectedTokenException();
                    }

                    byte firstByte = this.jsonBinaryBuffer.Peek();
                    jsonTokenType = JsonBinaryReader.GetJsonTokenType(firstByte);
                    if ((jsonTokenType == JsonTokenType.String) && this.JsonObjectState.IsPropertyExpected)
                    {
                        jsonTokenType = JsonTokenType.FieldName;
                    }

                    // 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
                    if ((jsonTokenType == JsonTokenType.BeginArray) || (jsonTokenType == JsonTokenType.BeginObject))
                    {
                        if (!JsonBinaryEncoding.TryGetValueLength(
                            this.jsonBinaryBuffer.GetBufferedRawJsonToken().Span,
                            out int arrayOrObjectLength))
                        {
                            throw new JsonUnexpectedTokenException();
                        }

                        this.arrayAndObjectEndStack.Push(this.jsonBinaryBuffer.Position + arrayOrObjectLength);
                        nextTokenOffset = JsonBinaryReader.GetArrayOrObjectPrefixLength(firstByte);
                    }
                    else
                    {
                        if (!JsonBinaryEncoding.TryGetValueLength(
                            this.jsonBinaryBuffer.GetBufferedRawJsonToken().Span,
                            out nextTokenOffset))
                        {
                            throw new JsonUnexpectedTokenException();
                        }
                    }
                }

                this.JsonObjectState.RegisterToken(jsonTokenType);
                this.currentTokenPosition = this.jsonBinaryBuffer.Position;
                this.jsonBinaryBuffer.SkipBytes(nextTokenOffset);
                return true;
            }
 private BinaryNode CreateBinaryNode(int offset)
 {
     return(new BinaryNode(offset, JsonBinaryEncoding.GetNodeType(this.buffer[offset])));
 }
            /// <summary>
            /// Gets the number of properties in an object node.
            /// </summary>
            /// <param name="objectNavigatorNode">The <see cref="IJsonNavigatorNode"/> of node to get the property count from.</param>
            /// <returns>The number of properties in an object node.</returns>
            public override int GetObjectPropertyCount(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 be a binary object node.");
                }

                int  objectOffset = ((BinaryNode)objectNavigatorNode).Offset;
                byte typeMarker   = this.buffer[objectOffset];
                int  firstObjectPropertyOffset = objectOffset + JsonBinaryEncoding.GetFirstValueOffset(typeMarker);
                long count;

                switch (typeMarker)
                {
                // Empty and Single Object
                case JsonBinaryEncoding.TypeMarker.EmptyObject:
                    count = 0;
                    break;

                case JsonBinaryEncoding.TypeMarker.SinglePropertyObject:
                    // This number gets divided by 2 later.
                    count = 2;
                    break;

                // Object with length and count prefix
                case JsonBinaryEncoding.TypeMarker.Object1ByteLengthAndCount:
                    count = this.buffer[objectOffset + JsonBinaryEncoding.TypeMarkerLength + JsonBinaryEncoding.OneByteLength];
                    break;

                case JsonBinaryEncoding.TypeMarker.Object2ByteLengthAndCount:
                    count = BitConverter.ToUInt16(this.buffer, objectOffset + JsonBinaryEncoding.TypeMarkerLength + JsonBinaryEncoding.TwoByteLength);
                    break;

                case JsonBinaryEncoding.TypeMarker.Object4ByteLengthAndCount:
                    count = BitConverter.ToUInt32(this.buffer, objectOffset + JsonBinaryEncoding.TypeMarkerLength + JsonBinaryEncoding.FourByteLength);
                    break;

                // Object with length prefix
                case JsonBinaryEncoding.TypeMarker.Object1ByteLength:
                    count = this.GetValueCount(firstObjectPropertyOffset, this.buffer[objectOffset + JsonBinaryEncoding.TypeMarkerLength]);
                    break;

                case JsonBinaryEncoding.TypeMarker.Object2ByteLength:
                    count = this.GetValueCount(firstObjectPropertyOffset, BitConverter.ToUInt16(this.buffer, objectOffset + JsonBinaryEncoding.TypeMarkerLength));
                    break;

                case JsonBinaryEncoding.TypeMarker.Object4ByteLength:
                    count = this.GetValueCount(firstObjectPropertyOffset, BitConverter.ToUInt32(this.buffer, objectOffset + JsonBinaryEncoding.TypeMarkerLength));
                    break;

                default:
                    throw new InvalidOperationException($"Unexpected object type marker: {typeMarker}");
                }

                // Divide by 2 since the count includes fieldname and value as seperate entities
                count = count / 2;
                if (count > int.MaxValue)
                {
                    throw new InvalidOperationException("count can not be more than int.MaxValue");
                }

                return((int)count);
            }
            /// <summary>
            /// Gets the number of elements in an array node.
            /// </summary>
            /// <param name="arrayNavigatorNode">The <see cref="IJsonNavigatorNode"/> of the (array) node to get the count of.</param>
            /// <returns>The number of elements in the array node.</returns>
            public override int GetArrayItemCount(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  offset           = ((BinaryNode)arrayNavigatorNode).Offset;
                byte typeMarker       = this.buffer[offset];
                int  firstValueOffset = offset + JsonBinaryEncoding.GetFirstValueOffset(typeMarker);
                long count;

                switch (typeMarker)
                {
                // Empty and Single Array
                case JsonBinaryEncoding.TypeMarker.EmptyArray:
                    count = 0;
                    break;

                case JsonBinaryEncoding.TypeMarker.SingleItemArray:
                    count = 1;
                    break;

                // Arrays with length and count prefix
                case JsonBinaryEncoding.TypeMarker.Array1ByteLengthAndCount:
                    count = this.buffer[offset + JsonBinaryEncoding.TypeMarkerLength + JsonBinaryEncoding.OneByteLength];
                    break;

                case JsonBinaryEncoding.TypeMarker.Array2ByteLengthAndCount:
                    count = BitConverter.ToUInt16(this.buffer, offset + JsonBinaryEncoding.TypeMarkerLength + JsonBinaryEncoding.TwoByteLength);
                    break;

                case JsonBinaryEncoding.TypeMarker.Array4ByteLengthAndCount:
                    count = BitConverter.ToUInt32(this.buffer, offset + JsonBinaryEncoding.TypeMarkerLength + JsonBinaryEncoding.FourByteLength);
                    break;

                // Arrays with length prefix
                case JsonBinaryEncoding.TypeMarker.Array1ByteLength:
                    count = this.GetValueCount(firstValueOffset, this.buffer[offset + JsonBinaryEncoding.TypeMarkerLength]);
                    break;

                case JsonBinaryEncoding.TypeMarker.Array2ByteLength:
                    count = this.GetValueCount(firstValueOffset, BitConverter.ToUInt16(this.buffer, offset + JsonBinaryEncoding.TypeMarkerLength));
                    break;

                case JsonBinaryEncoding.TypeMarker.Array4ByteLength:
                    count = this.GetValueCount(firstValueOffset, BitConverter.ToUInt32(this.buffer, offset + JsonBinaryEncoding.TypeMarkerLength));
                    break;

                default:
                    throw new InvalidOperationException($"Unexpected array type marker: {typeMarker}");
                }

                if (count > int.MaxValue)
                {
                    throw new InvalidOperationException("count can not be more than int.MaxValue");
                }

                return((int)count);
            }
Example #12
0
            private void WriteToInternal(BinaryNavigatorNode binaryNavigatorNode, IJsonWriter jsonWriter, bool sameEncoding)
            {
                ReadOnlyMemory <byte> buffer   = binaryNavigatorNode.Buffer;
                JsonNodeType          nodeType = binaryNavigatorNode.JsonNodeType;

                if (sameEncoding && this.TryGetBufferedRawJsonInternal(binaryNavigatorNode, out ReadOnlyMemory <byte> bufferedRawJson))
                {
                    // Token type doesn't make any difference other than whether it's a value or field name
                    JsonTokenType tokenType = nodeType == JsonNodeType.FieldName ? JsonTokenType.FieldName : JsonTokenType.String;
                    jsonWriter.WriteRawJsonToken(tokenType, bufferedRawJson.Span);
                    return;
                }

                switch (nodeType)
                {
                case JsonNodeType.Null:
                    jsonWriter.WriteNullValue();
                    break;

                case JsonNodeType.False:
                    jsonWriter.WriteBoolValue(false);
                    break;

                case JsonNodeType.True:
                    jsonWriter.WriteBoolValue(true);
                    break;

                case JsonNodeType.Number64:
                {
                    Number64 value = JsonBinaryEncoding.GetNumberValue(buffer.Span);
                    jsonWriter.WriteNumber64Value(value);
                }
                break;

                case JsonNodeType.String:
                case JsonNodeType.FieldName:
                    bool fieldName = binaryNavigatorNode.JsonNodeType == JsonNodeType.FieldName;

                    Utf8Memory utf8Buffer = Utf8Memory.UnsafeCreateNoValidation(buffer);
                    if (JsonBinaryEncoding.TryGetBufferedStringValue(
                            utf8Buffer,
                            this.jsonStringDictionary,
                            out Utf8Memory bufferedStringValue))
                    {
                        if (fieldName)
                        {
                            jsonWriter.WriteFieldName(bufferedStringValue.Span);
                        }
                        else
                        {
                            jsonWriter.WriteStringValue(bufferedStringValue.Span);
                        }
                    }
                    else
                    {
                        string value = JsonBinaryEncoding.GetStringValue(
                            utf8Buffer,
                            this.jsonStringDictionary);
                        if (fieldName)
                        {
                            jsonWriter.WriteFieldName(value);
                        }
                        else
                        {
                            jsonWriter.WriteStringValue(value);
                        }
                    }
                    break;

                case JsonNodeType.Array:
                {
                    jsonWriter.WriteArrayStart();

                    foreach (BinaryNavigatorNode arrayItem in this.GetArrayItemsInternal(buffer))
                    {
                        this.WriteToInternal(arrayItem, jsonWriter, sameEncoding);
                    }

                    jsonWriter.WriteArrayEnd();
                }
                break;

                case JsonNodeType.Object:
                {
                    jsonWriter.WriteObjectStart();

                    foreach (ObjectPropertyInternal objectProperty in this.GetObjectPropertiesInternal(buffer))
                    {
                        this.WriteToInternal(objectProperty.NameNode, jsonWriter, sameEncoding);
                        this.WriteToInternal(objectProperty.ValueNode, jsonWriter, sameEncoding);
                    }

                    jsonWriter.WriteObjectEnd();
                }
                break;

                case JsonNodeType.Int8:
                {
                    sbyte value = JsonBinaryEncoding.GetInt8Value(buffer.Span);
                    jsonWriter.WriteInt8Value(value);
                }
                break;

                case JsonNodeType.Int16:
                {
                    short value = JsonBinaryEncoding.GetInt16Value(buffer.Span);
                    jsonWriter.WriteInt16Value(value);
                }
                break;

                case JsonNodeType.Int32:
                {
                    int value = JsonBinaryEncoding.GetInt32Value(buffer.Span);
                    jsonWriter.WriteInt32Value(value);
                }
                break;

                case JsonNodeType.Int64:
                {
                    long value = JsonBinaryEncoding.GetInt64Value(buffer.Span);
                    jsonWriter.WriteInt64Value(value);
                }
                break;

                case JsonNodeType.UInt32:
                {
                    uint value = JsonBinaryEncoding.GetUInt32Value(buffer.Span);
                    jsonWriter.WriteUInt32Value(value);
                }
                break;

                case JsonNodeType.Float32:
                {
                    float value = JsonBinaryEncoding.GetFloat32Value(buffer.Span);
                    jsonWriter.WriteFloat32Value(value);
                }
                break;

                case JsonNodeType.Float64:
                {
                    double value = JsonBinaryEncoding.GetFloat64Value(buffer.Span);
                    jsonWriter.WriteFloat64Value(value);
                }
                break;

                case JsonNodeType.Binary:
                {
                    ReadOnlyMemory <byte> value = JsonBinaryEncoding.GetBinaryValue(buffer);
                    jsonWriter.WriteBinaryValue(value.Span);
                }
                break;

                case JsonNodeType.Guid:
                {
                    Guid value = JsonBinaryEncoding.GetGuidValue(buffer.Span);
                    jsonWriter.WriteGuidValue(value);
                }
                break;

                default:
                    throw new ArgumentOutOfRangeException($"Unknown {nameof(JsonNodeType)}: {nodeType}.");
                }
            }
        private static bool TryGetBufferedLengthPrefixedString(
            Utf8Memory stringToken,
            out Utf8Memory value)
        {
            ReadOnlySpan <byte> stringTokenSpan = stringToken.Memory.Span;
            byte typeMarker = stringTokenSpan[0];

            stringTokenSpan = stringTokenSpan.Slice(start: 1);

            int  start;
            long length;

            if (JsonBinaryEncoding.TypeMarker.IsEncodedLengthString(typeMarker))
            {
                start  = JsonBinaryEncoding.TypeMarkerLength;
                length = JsonBinaryEncoding.GetStringLengths(typeMarker);
            }
            else
            {
                switch (typeMarker)
                {
                case JsonBinaryEncoding.TypeMarker.String1ByteLength:
                    if (stringTokenSpan.Length < JsonBinaryEncoding.OneByteLength)
                    {
                        value = default;
                        return(false);
                    }

                    start  = JsonBinaryEncoding.TypeMarkerLength + JsonBinaryEncoding.OneByteLength;
                    length = stringTokenSpan[0];
                    break;

                case JsonBinaryEncoding.TypeMarker.String2ByteLength:
                    if (stringTokenSpan.Length < JsonBinaryEncoding.TwoByteLength)
                    {
                        value = default;
                        return(false);
                    }

                    start  = JsonBinaryEncoding.TypeMarkerLength + JsonBinaryEncoding.TwoByteLength;
                    length = MemoryMarshal.Read <ushort>(stringTokenSpan);
                    break;

                case JsonBinaryEncoding.TypeMarker.String4ByteLength:
                    if (stringTokenSpan.Length < JsonBinaryEncoding.FourByteLength)
                    {
                        value = default;
                        return(false);
                    }

                    start  = JsonBinaryEncoding.TypeMarkerLength + JsonBinaryEncoding.FourByteLength;
                    length = MemoryMarshal.Read <uint>(stringTokenSpan);
                    break;

                default:
                    value = default;
                    return(false);
                }

                if ((start + length) > stringToken.Length)
                {
                    value = default;
                    return(false);
                }
            }

            value = stringToken.Slice(start: start, length: (int)length);
            return(true);
        }
Example #14
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);
            }
Example #15
0
 public static bool TryGetInt8Value(
     ReadOnlySpan <byte> int8Token,
     out sbyte int8Value) => JsonBinaryEncoding.TryGetFixedWidthValue <sbyte>(
     int8Token,
     JsonBinaryEncoding.TypeMarker.Int8,
     out int8Value);
Example #16
0
            private void WriteFieldNameOrString(bool isFieldName, ReadOnlySpan <byte> utf8String)
            {
                // String dictionary encoding is currently performed only for field names.
                // This would be changed later, so that the writer can control which strings need to be encoded.
                this.JsonObjectState.RegisterToken(isFieldName ? JsonTokenType.FieldName : JsonTokenType.String);
                if (JsonBinaryEncoding.TryGetEncodedStringTypeMarker(
                        utf8String,
                        this.JsonObjectState.CurrentTokenType == JsonTokenType.FieldName ? this.jsonStringDictionary : null,
                        out JsonBinaryEncoding.MultiByteTypeMarker multiByteTypeMarker))
                {
                    switch (multiByteTypeMarker.Length)
                    {
                    case 1:
                        this.binaryWriter.Write(multiByteTypeMarker.One);
                        break;

                    case 2:
                        this.binaryWriter.Write(multiByteTypeMarker.One);
                        this.binaryWriter.Write(multiByteTypeMarker.Two);
                        break;

                    default:
                        throw new ArgumentOutOfRangeException($"Unable to serialize a {nameof(JsonBinaryEncoding.MultiByteTypeMarker)} of length: {multiByteTypeMarker.Length}");
                    }
                }
                else
                {
                    // See if the string length can be encoded into a single type marker
                    byte typeMarker = JsonBinaryEncoding.TypeMarker.GetEncodedStringLengthTypeMarker(utf8String.Length);
                    if (JsonBinaryEncoding.TypeMarker.IsValid(typeMarker))
                    {
                        this.binaryWriter.Write(typeMarker);
                    }
                    else
                    {
                        // Just write the type marker and the corresponding length
                        if (utf8String.Length < byte.MaxValue)
                        {
                            this.binaryWriter.Write(JsonBinaryEncoding.TypeMarker.String1ByteLength);
                            this.binaryWriter.Write((byte)utf8String.Length);
                        }
                        else if (utf8String.Length < ushort.MaxValue)
                        {
                            this.binaryWriter.Write(JsonBinaryEncoding.TypeMarker.String2ByteLength);
                            this.binaryWriter.Write((ushort)utf8String.Length);
                        }
                        else
                        {
                            // (utf8String.Length < uint.MaxValue)
                            this.binaryWriter.Write(JsonBinaryEncoding.TypeMarker.String4ByteLength);
                            this.binaryWriter.Write((uint)utf8String.Length);
                        }
                    }

                    // Finally write the string itself.
                    this.binaryWriter.Write(utf8String);
                }

                if (!isFieldName)
                {
                    // If we just wrote a string then increment the count (we don't increment for field names, since we need to wait for the corresponding property value).
                    this.bufferedContexts.Peek().Count++;
                }
            }
Example #17
0
 public static bool TryGetInt16Value(
     ReadOnlySpan <byte> int16Token,
     out short int16Value) => JsonBinaryEncoding.TryGetFixedWidthValue <short>(
     int16Token,
     JsonBinaryEncoding.TypeMarker.Int16,
     out int16Value);
 public static bool TryGetValueLength(ReadOnlySpan <byte> buffer, out int length)
 {
     // Too lazy to convert this right now.
     length = (int)JsonBinaryEncoding.GetValueLength(buffer);
     return(true);
 }
Example #19
0
 public static bool TryGetInt32Value(
     ReadOnlySpan <byte> int32Token,
     out int int32Value) => JsonBinaryEncoding.TryGetFixedWidthValue <int>(
     int32Token,
     JsonBinaryEncoding.TypeMarker.Int32,
     out int32Value);
Example #20
0
            private void WriteToInternal(BinaryNavigatorNode binaryNavigatorNode, IJsonWriter jsonWriter)
            {
                ReadOnlyMemory <byte> buffer   = binaryNavigatorNode.Buffer;
                JsonNodeType          nodeType = binaryNavigatorNode.JsonNodeType;

                switch (nodeType)
                {
                case JsonNodeType.Null:
                    jsonWriter.WriteNullValue();
                    break;

                case JsonNodeType.False:
                    jsonWriter.WriteBoolValue(false);
                    break;

                case JsonNodeType.True:
                    jsonWriter.WriteBoolValue(true);
                    break;

                case JsonNodeType.Number64:
                {
                    Number64 value = JsonBinaryEncoding.GetNumberValue(buffer.Span);
                    jsonWriter.WriteNumber64Value(value);
                }
                break;

                case JsonNodeType.String:
                case JsonNodeType.FieldName:
                    bool fieldName = binaryNavigatorNode.JsonNodeType == JsonNodeType.FieldName;

                    if (JsonBinaryEncoding.TryGetBufferedStringValue(
                            this.rootBuffer,
                            buffer,
                            out Utf8Memory bufferedStringValue))
                    {
                        if (fieldName)
                        {
                            jsonWriter.WriteFieldName(bufferedStringValue.Span);
                        }
                        else
                        {
                            jsonWriter.WriteStringValue(bufferedStringValue.Span);
                        }
                    }
                    else
                    {
                        string value = JsonBinaryEncoding.GetStringValue(
                            this.rootBuffer,
                            buffer);
                        if (fieldName)
                        {
                            jsonWriter.WriteFieldName(value);
                        }
                        else
                        {
                            jsonWriter.WriteStringValue(value);
                        }
                    }
                    break;

                case JsonNodeType.Array:
                {
                    jsonWriter.WriteArrayStart();

                    foreach (BinaryNavigatorNode arrayItem in this.GetArrayItemsInternal(buffer))
                    {
                        this.WriteToInternal(arrayItem, jsonWriter);
                    }

                    jsonWriter.WriteArrayEnd();
                }
                break;

                case JsonNodeType.Object:
                {
                    jsonWriter.WriteObjectStart();

                    foreach (ObjectPropertyInternal objectProperty in this.GetObjectPropertiesInternal(buffer))
                    {
                        this.WriteToInternal(objectProperty.NameNode, jsonWriter);
                        this.WriteToInternal(objectProperty.ValueNode, jsonWriter);
                    }

                    jsonWriter.WriteObjectEnd();
                }
                break;

                case JsonNodeType.Int8:
                {
                    sbyte value = JsonBinaryEncoding.GetInt8Value(buffer.Span);
                    jsonWriter.WriteInt8Value(value);
                }
                break;

                case JsonNodeType.Int16:
                {
                    short value = JsonBinaryEncoding.GetInt16Value(buffer.Span);
                    jsonWriter.WriteInt16Value(value);
                }
                break;

                case JsonNodeType.Int32:
                {
                    int value = JsonBinaryEncoding.GetInt32Value(buffer.Span);
                    jsonWriter.WriteInt32Value(value);
                }
                break;

                case JsonNodeType.Int64:
                {
                    long value = JsonBinaryEncoding.GetInt64Value(buffer.Span);
                    jsonWriter.WriteInt64Value(value);
                }
                break;

                case JsonNodeType.UInt32:
                {
                    uint value = JsonBinaryEncoding.GetUInt32Value(buffer.Span);
                    jsonWriter.WriteUInt32Value(value);
                }
                break;

                case JsonNodeType.Float32:
                {
                    float value = JsonBinaryEncoding.GetFloat32Value(buffer.Span);
                    jsonWriter.WriteFloat32Value(value);
                }
                break;

                case JsonNodeType.Float64:
                {
                    double value = JsonBinaryEncoding.GetFloat64Value(buffer.Span);
                    jsonWriter.WriteFloat64Value(value);
                }
                break;

                case JsonNodeType.Binary:
                {
                    ReadOnlyMemory <byte> value = JsonBinaryEncoding.GetBinaryValue(buffer);
                    jsonWriter.WriteBinaryValue(value.Span);
                }
                break;

                case JsonNodeType.Guid:
                {
                    Guid value = JsonBinaryEncoding.GetGuidValue(buffer.Span);
                    jsonWriter.WriteGuidValue(value);
                }
                break;

                default:
                    throw new ArgumentOutOfRangeException($"Unknown {nameof(JsonNodeType)}: {nodeType}.");
                }
            }
 public static bool TryGetGuidValue(
     ReadOnlySpan <byte> guidToken,
     out Guid guidValue) => JsonBinaryEncoding.TryGetFixedWidthValue <Guid>(
     guidToken,
     JsonBinaryEncoding.TypeMarker.Guid,
     out guidValue);