private static bool HandleEndArray(
            JsonSerializerOptions options,
            ref ReadStack state)
        {
            bool lastFrame = state.IsLastFrame;

            if (state.Current.Drain)
            {
                // The array is not being applied to the object.
                state.Pop();
                return(lastFrame);
            }

            IEnumerable value = ReadStackFrame.GetEnumerableValue(ref state.Current);

            if (state.Current.TempEnumerableValues != null)
            {
                // We have a converter; possibilities:
                // - Add value to current frame's current property or TempEnumerableValues.
                // - Add value to previous frame's current property or TempEnumerableValues.
                // - Set current property on current frame to value.
                // - Set current property on previous frame to value.
                // - Set ReturnValue if root frame and value is the actual return value.
                JsonEnumerableConverter converter = state.Current.JsonPropertyInfo.EnumerableConverter;
                Debug.Assert(converter != null);

                value = converter.CreateFromList(ref state, (IList)value, options);
                state.Current.TempEnumerableValues = null;
            }
            else if (state.Current.IsProcessingProperty(ClassType.Enumerable))
            {
                // We added the items to the list already.
                state.Current.EndProperty();
                return(false);
            }

            if (lastFrame)
            {
                if (state.Current.ReturnValue == null)
                {
                    // Returning a converted list or object.
                    state.Current.Reset();
                    state.Current.ReturnValue = value;
                    return(true);
                }
                else if (state.Current.IsProcessingCollectionObject())
                {
                    // Returning a non-converted list.
                    return(true);
                }
                // else there must be an outer object, so we'll return false here.
            }
            else if (state.Current.IsProcessingObject(ClassType.Enumerable))
            {
                state.Pop();
            }

            ApplyObjectToEnumerable(value, ref state);
            return(false);
        }
Example #2
0
        private static void HandleEndObject(ref ReadStack state)
        {
            // Only allow dictionaries to be processed here if this is the DataExtensionProperty.
            Debug.Assert(!state.Current.IsProcessingDictionary() || state.Current.JsonClassInfo.DataExtensionProperty == state.Current.JsonPropertyInfo);

            // Check if we are trying to build the sorted cache.
            if (state.Current.PropertyRefCache != null)
            {
                state.Current.JsonClassInfo.UpdateSortedPropertyCache(ref state.Current);
            }

            object value = state.Current.ReturnValue;

            if (state.IsLastFrame)
            {
                state.Current.Reset();
                state.Current.ReturnValue = value;
            }
            else
            {
                state.Pop();

                ApplyObjectToEnumerable(value, ref state);
            }
        }
Example #3
0
        private static void HandleEndObject(ref ReadStack state)
        {
            // Only allow dictionaries to be processed here if this is the DataExtensionProperty.
            Debug.Assert(
                (!state.Current.IsProcessingDictionary() || state.Current.JsonClassInfo.DataExtensionProperty == state.Current.JsonPropertyInfo) &&
                !state.Current.IsProcessingIDictionaryConstructible());

            if (state.Current.JsonClassInfo.ClassType == ClassType.Value)
            {
                // We should be in a converter, thus we must have bad JSON.
                ThrowHelper.ThrowJsonException_DeserializeUnableToConvertValue(state.Current.JsonPropertyInfo.RuntimePropertyType);
            }

            // Check if we are trying to build the sorted cache.
            if (state.Current.PropertyRefCache != null)
            {
                state.Current.JsonClassInfo.UpdateSortedPropertyCache(ref state.Current);
            }

            object value = state.Current.ReturnValue;

            if (state.IsLastFrame)
            {
                state.Current.Reset();
                state.Current.ReturnValue = value;
            }
            else
            {
                state.Pop();
                ApplyObjectToEnumerable(value, ref state);
            }
        }
        private static void HandleEndDictionary(JsonSerializerOptions options, ref ReadStack state)
        {
            Debug.Assert(!state.Current.SkipProperty && state.Current.JsonPropertyInfo != null);

            if (state.Current.IsProcessingProperty(ClassType.Dictionary))
            {
                if (state.Current.TempDictionaryValues != null)
                {
                    JsonDictionaryConverter?converter = state.Current.JsonPropertyInfo.DictionaryConverter;
                    Debug.Assert(converter != null);
                    state.Current.JsonPropertyInfo.SetValueAsObject(state.Current.ReturnValue, converter.CreateFromDictionary(ref state, state.Current.TempDictionaryValues, options));
                    state.Current.EndProperty();
                }
                else
                {
                    Debug.Assert(state.Current.JsonClassInfo != null);

                    // Handle special case of DataExtensionProperty where we just added a dictionary element to the extension property.
                    // Since the JSON value is not a dictionary element (it's a normal property in JSON) a JsonTokenType.EndObject
                    // encountered here is from the outer object so forward to HandleEndObject().
                    if (state.Current.JsonClassInfo.DataExtensionProperty == state.Current.JsonPropertyInfo)
                    {
                        HandleEndObject(ref state);
                    }
                    else
                    {
                        // We added the items to the dictionary already.
                        state.Current.EndProperty();
                    }
                }
            }
            else
            {
                object?value;
                if (state.Current.TempDictionaryValues != null)
                {
                    JsonDictionaryConverter?converter = state.Current.JsonPropertyInfo.DictionaryConverter;
                    Debug.Assert(converter != null);
                    value = converter.CreateFromDictionary(ref state, state.Current.TempDictionaryValues, options);
                }
                else
                {
                    value = state.Current.ReturnValue;
                }

                if (state.IsLastFrame)
                {
                    // Set the return value directly since this will be returned to the user.
                    state.Current.Reset();
                    state.Current.ReturnValue = value;
                }
                else
                {
                    state.Pop();
                    ApplyObjectToEnumerable(value, ref state);
                }
            }
        }
        private static void HandleEndDictionary(JsonSerializerOptions options, ref Utf8JsonReader reader, ref ReadStack state)
        {
            if (state.Current.SkipProperty)
            {
                return;
            }

            if (state.Current.IsDictionaryProperty)
            {
                // We added the items to the dictionary already.
                state.Current.EndProperty();
            }
            else if (state.Current.IsIDictionaryConstructibleProperty)
            {
                Debug.Assert(state.Current.TempDictionaryValues != null);
                JsonDictionaryConverter converter = state.Current.JsonPropertyInfo.DictionaryConverter;
                state.Current.JsonPropertyInfo.SetValueAsObject(state.Current.ReturnValue, converter.CreateFromDictionary(ref state, state.Current.TempDictionaryValues, options));
                state.Current.EndProperty();
            }
            else
            {
                object value;
                if (state.Current.TempDictionaryValues != null)
                {
                    JsonDictionaryConverter converter = state.Current.JsonPropertyInfo.DictionaryConverter;
                    value = converter.CreateFromDictionary(ref state, state.Current.TempDictionaryValues, options);
                }
                else
                {
                    value = state.Current.ReturnValue;
                }

                if (state.IsLastFrame)
                {
                    // Set the return value directly since this will be returned to the user.
                    state.Current.Reset();
                    state.Current.ReturnValue = value;
                }
                else
                {
                    state.Pop();
                    ApplyObjectToEnumerable(value, ref state, ref reader);
                }
            }
        }
        private static void HandleEndObject(JsonSerializerOptions options, ref Utf8JsonReader reader, ref ReadStack state)
        {
            Debug.Assert(!state.Current.IsProcessingDictionary && !state.Current.IsProcessingIDictionaryConstructible);

            state.Current.JsonClassInfo.UpdateSortedPropertyCache(ref state.Current);

            object value = state.Current.ReturnValue;

            if (state.IsLastFrame)
            {
                state.Current.Reset();
                state.Current.ReturnValue = value;
            }
            else
            {
                state.Pop();
                ApplyObjectToEnumerable(value, ref state, ref reader);
            }
        }
        private static void HandleEndObject(ref ReadStack state)
        {
            Debug.Assert(state.Current.JsonClassInfo != null);

            // Only allow dictionaries to be processed here if this is the DataExtensionProperty or if the dictionary is a preserved reference.
            Debug.Assert(!state.Current.IsProcessingDictionary() ||
                         state.Current.JsonClassInfo.DataExtensionProperty == state.Current.JsonPropertyInfo ||
                         (state.Current.IsProcessingObject(ClassType.Dictionary) && state.Current.ReferenceId != null));

            // Check if we are trying to build the sorted cache.
            if (state.Current.PropertyRefCache != null)
            {
                state.Current.JsonClassInfo.UpdateSortedPropertyCache(ref state.Current);
            }

            object?value;

            // Used for ReferenceHandling.Preserve
            if (state.Current.IsPreservedArray)
            {
                value = GetPreservedArrayValue(ref state);
            }
            else
            {
                value = state.Current.ReturnValue;
            }

            if (state.IsLastFrame)
            {
                state.Current.Reset();
                state.Current.ReturnValue = value;
            }
            else
            {
                // Set directly when handling non-nested preserved array
                bool setPropertyDirectly = state.Current.IsPreservedArray && !state.Current.IsNestedPreservedArray;
                state.Pop();

                ApplyObjectToEnumerable(value, ref state, setPropertyDirectly);
            }
        }
        private static void HandleEndDictionary(JsonSerializerOptions options, ref Utf8JsonReader reader, ref ReadStack state)
        {
            if (state.Current.IsDictionaryProperty)
            {
                // We added the items to the dictionary already.
                state.Current.ResetProperty();
            }
            else if (state.Current.IsImmutableDictionaryProperty)
            {
                Debug.Assert(state.Current.TempDictionaryValues != null);
                state.Current.JsonPropertyInfo.SetValueAsObject(state.Current.ReturnValue, CreateImmutableDictionaryFromTempValues(ref state, options));
                state.Current.ResetProperty();
            }
            else
            {
                object value;
                if (state.Current.TempDictionaryValues != null)
                {
                    value = CreateImmutableDictionaryFromTempValues(ref state, options);
                }
                else
                {
                    value = state.Current.ReturnValue;
                }

                if (state.IsLastFrame)
                {
                    // Set the return value directly since this will be returned to the user.
                    state.Current.Reset();
                    state.Current.ReturnValue = value;
                }
                else
                {
                    state.Pop();
                    ApplyObjectToEnumerable(value, ref state, ref reader);
                }
            }
        }
        private static bool HandleEndArray(
            JsonSerializerOptions options,
            ref ReadStack state)
        {
            bool lastFrame = state.IsLastFrame;

            if (state.Current.Drain)
            {
                // The array is not being applied to the object.
                state.Pop();
                return(lastFrame);
            }

            IEnumerable?value = ReadStackFrame.GetEnumerableValue(ref state.Current);
            bool        setPropertyDirectly = false;

            if (state.Current.TempEnumerableValues != null)
            {
                Debug.Assert(state.Current.JsonPropertyInfo != null);
                // We have a converter; possibilities:
                // - Add value to current frame's current property or TempEnumerableValues.
                // - Add value to previous frame's current property or TempEnumerableValues.
                // - Set current property on current frame to value.
                // - Set current property on previous frame to value.
                // - Set ReturnValue if root frame and value is the actual return value.
                JsonEnumerableConverter?converter = state.Current.JsonPropertyInfo.EnumerableConverter;
                Debug.Assert(converter != null);

                value = converter.CreateFromList(ref state, (IList)value !, options);
                state.Current.TempEnumerableValues = null;

                // Since we used a converter, we just processed an array or an immutable collection. This means we created a new enumerable object.
                // If we are processing an enumerable property, replace the current value of the property with the new instance.
                if (state.Current.IsProcessingProperty(ClassType.Enumerable))
                {
                    setPropertyDirectly = true;
                }
            }
            else if (state.Current.IsProcessingProperty(ClassType.Enumerable))
            {
                // We added the items to the list already.
                state.Current.EndProperty();
                return(false);
            }

            if (lastFrame)
            {
                if (state.Current.ReturnValue == null)
                {
                    // Returning a converted list or object.
                    state.Current.Reset();
                    state.Current.ReturnValue = value;
                    return(true);
                }
                else if (state.Current.IsProcessingCollectionObject())
                {
                    // Returning a non-converted list.
                    return(true);
                }
                // else there must be an outer object, so we'll return false here.
            }
            else if (state.Current.IsProcessingObject(ClassType.Enumerable))
            {
                state.Pop();
            }

            ApplyObjectToEnumerable(value, ref state, setPropertyDirectly);
            return(false);
        }
        private static void HandleEndDictionary(JsonSerializerOptions options, ref Utf8JsonReader reader, ref ReadStack state)
        {
            if (state.Current.IsDictionaryProperty)
            {
                // We added the items to the dictionary already.
                state.Current.ResetProperty();
            }
            else if (state.Current.IsIDictionaryConstructibleProperty)
            {
                Debug.Assert(state.Current.TempDictionaryValues != null);
                JsonDictionaryConverter converter = state.Current.JsonPropertyInfo.DictionaryConverter;
                state.Current.JsonPropertyInfo.SetValueAsObject(state.Current.ReturnValue, converter.CreateFromDictionary(ref state, state.Current.TempDictionaryValues, options));
                state.Current.ResetProperty();
            }
            else if (state.Current.IsKeyValuePairProperty)
            {
                JsonClassInfo elementClassInfo = state.Current.JsonPropertyInfo.ElementClassInfo;

                JsonPropertyInfo propertyInfo;
                if (elementClassInfo.ClassType == ClassType.KeyValuePair)
                {
                    propertyInfo = elementClassInfo.GetPolicyPropertyOfKeyValuePair();
                }
                else
                {
                    propertyInfo = elementClassInfo.GetPolicyProperty();
                }

                Debug.Assert(state.Current.TempDictionaryValues != null);
                state.Current.JsonPropertyInfo.SetValueAsObject(
                    state.Current.ReturnValue,
                    propertyInfo.CreateKeyValuePairInstance(ref state, state.Current.TempDictionaryValues, options));
                state.Current.ResetProperty();
            }
            else
            {
                object value;
                if (state.Current.TempDictionaryValues != null)
                {
                    if (state.Current.IsKeyValuePair)
                    {
                        JsonClassInfo elementClassInfo = state.Current.JsonClassInfo.ElementClassInfo;

                        JsonPropertyInfo propertyInfo;
                        if (elementClassInfo.ClassType == ClassType.KeyValuePair)
                        {
                            propertyInfo = elementClassInfo.GetPolicyPropertyOfKeyValuePair();
                        }
                        else
                        {
                            propertyInfo = elementClassInfo.GetPolicyProperty();
                        }

                        value = propertyInfo.CreateKeyValuePairInstance(ref state, state.Current.TempDictionaryValues, options);
                    }
                    else
                    {
                        JsonDictionaryConverter converter = state.Current.JsonPropertyInfo.DictionaryConverter;
                        value = converter.CreateFromDictionary(ref state, state.Current.TempDictionaryValues, options);
                    }
                }
                else
                {
                    value = state.Current.ReturnValue;
                }

                if (state.IsLastFrame)
                {
                    // Set the return value directly since this will be returned to the user.
                    state.Current.Reset();
                    state.Current.ReturnValue = value;
                }
                else
                {
                    state.Pop();
                    ApplyObjectToEnumerable(value, ref state, ref reader);
                }
            }
        }
Example #11
0
        private static void ReadCore(
            JsonSerializerOptions options,
            ref Utf8JsonReader reader,
            ref ReadStack readStack)
        {
            try
            {
                JsonReaderState initialState         = default;
                long            initialBytesConsumed = default;

                while (true)
                {
                    if (readStack.ReadAhead)
                    {
                        // When we're reading ahead we always have to save the state
                        // as we don't know if the next token is an opening object or
                        // array brace.
                        initialState         = reader.CurrentState;
                        initialBytesConsumed = reader.BytesConsumed;
                    }

                    if (!reader.Read())
                    {
                        // Need more data
                        break;
                    }

                    JsonTokenType tokenType = reader.TokenType;

                    if (options.ReferenceHandling.ShouldReadPreservedReferences())
                    {
                        CheckValidTokenAfterMetadataValues(ref readStack, tokenType);
                    }

                    if (JsonHelpers.IsInRangeInclusive(tokenType, JsonTokenType.String, JsonTokenType.False))
                    {
                        Debug.Assert(tokenType == JsonTokenType.String || tokenType == JsonTokenType.Number || tokenType == JsonTokenType.True || tokenType == JsonTokenType.False);

                        HandleValue(tokenType, options, ref reader, ref readStack);
                    }
                    else if (tokenType == JsonTokenType.PropertyName)
                    {
                        HandlePropertyName(options, ref reader, ref readStack);
                    }
                    else if (tokenType == JsonTokenType.StartObject)
                    {
                        if (readStack.Current.SkipProperty)
                        {
                            readStack.Push();
                            readStack.Current.Drain = true;
                        }
                        else if (readStack.Current.IsProcessingValue())
                        {
                            if (!HandleObjectAsValue(tokenType, options, ref reader, ref readStack, ref initialState, initialBytesConsumed))
                            {
                                // Need more data
                                break;
                            }
                        }
                        else if (readStack.Current.IsProcessingDictionary())
                        {
                            HandleStartDictionary(options, ref readStack);
                        }
                        else
                        {
                            HandleStartObject(options, ref readStack);
                        }
                    }
                    else if (tokenType == JsonTokenType.EndObject)
                    {
                        if (readStack.Current.Drain)
                        {
                            readStack.Pop();

                            // Clear the current property in case it is a dictionary, since dictionaries must have EndProperty() called when completed.
                            // A non-dictionary property can also have EndProperty() called when completed, although it is redundant.
                            readStack.Current.EndProperty();
                        }
                        else if (readStack.Current.ReferenceId != null)
                        {
                            Debug.Assert(options.ReferenceHandling.ShouldReadPreservedReferences());

                            HandleReference(ref readStack);
                        }
                        else if (readStack.Current.IsProcessingDictionary())
                        {
                            HandleEndDictionary(options, ref readStack);
                        }
                        else
                        {
                            HandleEndObject(ref readStack);
                        }
                    }
                    else if (tokenType == JsonTokenType.StartArray)
                    {
                        if (!readStack.Current.IsProcessingValue())
                        {
                            HandleStartArray(options, ref readStack);
                        }
                        else if (!HandleObjectAsValue(tokenType, options, ref reader, ref readStack, ref initialState, initialBytesConsumed))
                        {
                            // Need more data
                            break;
                        }
                    }
                    else if (tokenType == JsonTokenType.EndArray)
                    {
                        HandleEndArray(options, ref readStack);
                    }
                    else if (tokenType == JsonTokenType.Null)
                    {
                        HandleNull(options, ref reader, ref readStack);
                    }
                }
            }
            catch (JsonReaderException ex)
            {
                // Re-throw with Path information.
                ThrowHelper.ReThrowWithPath(readStack, ex);
            }
            catch (FormatException ex) when(ex.Source == ThrowHelper.ExceptionSourceValueToRethrowAsJsonException)
            {
                ThrowHelper.ReThrowWithPath(readStack, reader, ex);
            }
            catch (InvalidOperationException ex) when(ex.Source == ThrowHelper.ExceptionSourceValueToRethrowAsJsonException)
            {
                ThrowHelper.ReThrowWithPath(readStack, reader, ex);
            }
            catch (JsonException ex)
            {
                ThrowHelper.AddExceptionInformation(readStack, reader, ex);
                throw;
            }

            readStack.BytesConsumed += reader.BytesConsumed;
        }
Example #12
0
        private static void ReadCore(
            JsonSerializerOptions options,
            ref Utf8JsonReader reader,
            ref ReadStack readStack)
        {
            try
            {
                JsonReaderState initialState         = default;
                long            initialBytesConsumed = default;

                while (true)
                {
                    if (readStack.ReadAhead)
                    {
                        // When we're reading ahead we always have to save the state
                        // as we don't know if the next token is an opening object or
                        // array brace.
                        initialState         = reader.CurrentState;
                        initialBytesConsumed = reader.BytesConsumed;
                    }

                    if (!reader.Read())
                    {
                        // Need more data
                        break;
                    }

                    JsonTokenType tokenType = reader.TokenType;

                    if (JsonHelpers.IsInRangeInclusive(tokenType, JsonTokenType.String, JsonTokenType.False))
                    {
                        Debug.Assert(tokenType == JsonTokenType.String || tokenType == JsonTokenType.Number || tokenType == JsonTokenType.True || tokenType == JsonTokenType.False);

                        HandleValue(tokenType, options, ref reader, ref readStack);
                    }
                    else if (tokenType == JsonTokenType.PropertyName)
                    {
                        HandlePropertyName(options, ref reader, ref readStack);
                    }
                    else if (tokenType == JsonTokenType.StartObject)
                    {
                        if (readStack.Current.SkipProperty)
                        {
                            readStack.Push();
                            readStack.Current.Drain = true;
                        }
                        else if (readStack.Current.IsProcessingValue(tokenType))
                        {
                            if (!HandleObjectAsValue(tokenType, options, ref reader, ref readStack, ref initialState, initialBytesConsumed))
                            {
                                // Need more data
                                break;
                            }
                        }
                        else if (readStack.Current.IsProcessingDictionary || readStack.Current.IsProcessingIDictionaryConstructible)
                        {
                            HandleStartDictionary(options, ref reader, ref readStack);
                        }
                        else
                        {
                            HandleStartObject(options, ref reader, ref readStack);
                        }
                    }
                    else if (tokenType == JsonTokenType.EndObject)
                    {
                        if (readStack.Current.Drain)
                        {
                            readStack.Pop();
                        }
                        else if (readStack.Current.IsProcessingDictionary || readStack.Current.IsProcessingIDictionaryConstructible)
                        {
                            HandleEndDictionary(options, ref reader, ref readStack);
                        }
                        else
                        {
                            HandleEndObject(options, ref reader, ref readStack);
                        }
                    }
                    else if (tokenType == JsonTokenType.StartArray)
                    {
                        if (!readStack.Current.IsProcessingValue(tokenType))
                        {
                            HandleStartArray(options, ref reader, ref readStack);
                        }
                        else if (!HandleObjectAsValue(tokenType, options, ref reader, ref readStack, ref initialState, initialBytesConsumed))
                        {
                            // Need more data
                            break;
                        }
                    }
                    else if (tokenType == JsonTokenType.EndArray)
                    {
                        HandleEndArray(options, ref reader, ref readStack);
                    }
                    else if (tokenType == JsonTokenType.Null)
                    {
                        HandleNull(ref reader, ref readStack, options);
                    }
                }
            }
            catch (JsonReaderException ex)
            {
                // Re-throw with Path information.
                ThrowHelper.ReThrowWithPath(readStack, ex);
            }
            catch (FormatException ex) when(ex.Source == ThrowHelper.ExceptionSourceValueToRethrowAsJsonException)
            {
                ThrowHelper.ReThrowWithPath(readStack, reader, ex);
            }
            catch (InvalidOperationException ex) when(ex.Source == ThrowHelper.ExceptionSourceValueToRethrowAsJsonException)
            {
                ThrowHelper.ReThrowWithPath(readStack, reader, ex);
            }
            catch (JsonException ex)
            {
                ThrowHelper.AddExceptionInformation(readStack, reader, ex);
                throw;
            }

            readStack.BytesConsumed += reader.BytesConsumed;
            return;
        }