private unsafe bool AboutToReadPropertyNameInternal(IJsonParser reader, JsonParserState state)
        {
            if (_state != State.None)
            {
                if (!AboutToReadWithStateUnlikely(reader, state))
                    return false;
            }

            _state = State.None;

            while (true)
            {
                if (reader.Read() == false)
                    return false;

                if (state.CurrentTokenType != JsonParserToken.String)
                    return true; // let the caller handle that

                if (_readingMetadataObject == false)
                {
                    if (state.StringSize == 9 && state.StringBuffer[0] == (byte)'@' && *(long*)(state.StringBuffer + 1) == 7022344802737087853)
                        _readingMetadataObject = true;

                    return true;
                }

                if (AboutToReadPropertyNameInMetadataUnlikely(reader, state, out bool aboutToReadPropertyName))
                    return aboutToReadPropertyName;
            }
        }
Example #2
0
 private bool ReadMaybeModifiedPropertyName()
 {
     if (_modifier != null)
     {
         return(_modifier.AboutToReadPropertyName(_reader, _state));
     }
     return(_reader.Read());
 }
 private bool ReadMaybeModifiedPropertyName()
 {
     return(_reader.Read());
 }
        public bool Read()
        {
            if (_continuationState.Count == 0)
            {
                return(false); //nothing to do
            }
            var currentState = _continuationState.Pop();

            while (true)
            {
                switch (currentState.State)
                {
                case ContinuationState.ReadObjectDocument:
                    if (_reader.Read() == false)
                    {
                        _continuationState.Push(currentState);
                        return(false);
                    }
                    currentState.State = ContinuationState.ReadObject;
                    continue;

                case ContinuationState.ReadArrayDocument:
                    if (_reader.Read() == false)
                    {
                        _continuationState.Push(currentState);
                        return(false);
                    }

                    var fakeFieldName = _context.GetLazyStringForFieldWithCaching("_");
                    var propIndex     = _context.CachedProperties.GetPropertyId(fakeFieldName);
                    currentState.CurrentPropertyId = propIndex;
                    currentState.MaxPropertyId     = propIndex;
                    currentState.FirstWrite        = _position;
                    currentState.Properties        = new List <PropertyTag>
                    {
                        new PropertyTag
                        {
                            PropertyId = propIndex
                        }
                    };
                    currentState.State = ContinuationState.CompleteDocumentArray;
                    _continuationState.Push(currentState);
                    currentState = new BuildingState
                    {
                        State = ContinuationState.ReadArray
                    };
                    continue;

                case ContinuationState.CompleteDocumentArray:
                    currentState.Properties[0].Type     = (byte)_writeToken.WrittenToken;
                    currentState.Properties[0].Position = _writeToken.ValuePos;

                    // Register property position, name id (PropertyId) and type (object type and metadata)
                    _writeToken = FinalizeObjectWrite(currentState.Properties, currentState.FirstWrite, currentState.MaxPropertyId);

                    return(true);

                case ContinuationState.ReadObject:
                    if (_state.CurrentTokenType != JsonParserToken.StartObject)
                    {
                        throw new InvalidDataException("Expected start of object, but got " + _state.CurrentTokenType);
                    }
                    currentState.State      = ContinuationState.ReadPropertyName;
                    currentState.Properties = new List <PropertyTag>();
                    currentState.FirstWrite = _position;
                    continue;

                case ContinuationState.ReadArray:
                    if (_state.CurrentTokenType != JsonParserToken.StartArray)
                    {
                        throw new InvalidDataException("Expected start of array, but got " + _state.CurrentTokenType);
                    }
                    currentState.Types     = new List <BlittableJsonToken>();
                    currentState.Positions = new List <int>();
                    currentState.State     = ContinuationState.ReadArrayValue;
                    continue;

                case ContinuationState.ReadArrayValue:
                    if (_reader.Read() == false)
                    {
                        _continuationState.Push(currentState);
                        return(false);
                    }
                    if (_state.CurrentTokenType == JsonParserToken.EndArray)
                    {
                        currentState.State = ContinuationState.CompleteArray;
                        continue;
                    }
                    currentState.State = ContinuationState.CompleteArrayValue;
                    _continuationState.Push(currentState);
                    currentState = new BuildingState
                    {
                        State = ContinuationState.ReadValue
                    };
                    continue;

                case ContinuationState.CompleteArrayValue:
                    currentState.Types.Add(_writeToken.WrittenToken);
                    currentState.Positions.Add(_writeToken.ValuePos);
                    currentState.State = ContinuationState.ReadArrayValue;
                    continue;

                case ContinuationState.CompleteArray:
                    var arrayInfoStart = _position;
                    var arrayToken     = BlittableJsonToken.StartArray;

                    _position += WriteVariableSizeInt(currentState.Positions.Count);
                    if (currentState.Positions.Count == 0)
                    {
                        arrayToken |= BlittableJsonToken.OffsetSizeByte;
                        _writeToken = new WriteToken
                        {
                            ValuePos     = arrayInfoStart,
                            WrittenToken = arrayToken
                        };
                    }
                    else
                    {
                        var distanceFromFirstItem = arrayInfoStart - currentState.Positions[0];
                        var distanceTypeSize      = SetOffsetSizeFlag(ref arrayToken, distanceFromFirstItem);

                        for (var i = 0; i < currentState.Positions.Count; i++)
                        {
                            WriteNumber(arrayInfoStart - currentState.Positions[i], distanceTypeSize);
                            _position += distanceTypeSize;

                            _stream.WriteByte((byte)currentState.Types[i]);
                            _position++;
                        }

                        _writeToken = new WriteToken
                        {
                            ValuePos     = arrayInfoStart,
                            WrittenToken = arrayToken
                        };
                    }
                    currentState = _continuationState.Pop();
                    continue;

                case ContinuationState.ReadPropertyName:
                    if (_reader.Read() == false)
                    {
                        _continuationState.Push(currentState);
                        return(false);
                    }

                    if (_state.CurrentTokenType == JsonParserToken.EndObject)
                    {
                        _writeToken = FinalizeObjectWrite(currentState.Properties, currentState.FirstWrite,
                                                          currentState.MaxPropertyId);
                        if (_continuationState.Count == 0)
                        {
                            return(true);
                        }
                        currentState = _continuationState.Pop();
                        continue;
                    }

                    if (_state.CurrentTokenType != JsonParserToken.String)
                    {
                        throw new InvalidDataException("Expected property, but got " + _state.CurrentTokenType);
                    }


                    var property = CreateLazyStringValueFromParserState();
                    if (_state.EscapePositions.Count > 0)
                    {
                        property.EscapePositions = _state.EscapePositions.ToArray();
                    }

                    currentState.CurrentPropertyId = _context.CachedProperties.GetPropertyId(property);
                    currentState.MaxPropertyId     = Math.Max(currentState.MaxPropertyId, currentState.CurrentPropertyId);
                    currentState.State             = ContinuationState.ReadPropertyValue;
                    continue;

                case ContinuationState.ReadPropertyValue:
                    if (_reader.Read() == false)
                    {
                        _continuationState.Push(currentState);
                        return(false);
                    }
                    currentState.State = ContinuationState.CompleteReadingPropertyValue;
                    _continuationState.Push(currentState);
                    currentState = new BuildingState
                    {
                        State = ContinuationState.ReadValue
                    };
                    continue;

                case ContinuationState.CompleteReadingPropertyValue:
                    // Register property position, name id (PropertyId) and type (object type and metadata)
                    currentState.Properties.Add(new PropertyTag
                    {
                        Position   = _writeToken.ValuePos,
                        Type       = (byte)_writeToken.WrittenToken,
                        PropertyId = currentState.CurrentPropertyId
                    });
                    currentState.State = ContinuationState.ReadPropertyName;
                    continue;

                case ContinuationState.ReadValue:
                    ReadJsonValue();
                    currentState = _continuationState.Pop();
                    break;
                }
            }
        }
Example #5
0
        private bool AboutToReadWithStateUnlikely(IJsonParser reader, JsonParserState state)
        {
            switch (_state)
            {
            case State.None:
                break;

            case State.IgnoreProperty:
                if (reader.Read() == false)
                {
                    return(false);
                }

                if (state.CurrentTokenType == JsonParserToken.StartArray ||
                    state.CurrentTokenType == JsonParserToken.StartObject)
                {
                    ThrowInvalidMetadataProperty(state);
                }
                break;

            case State.IgnoreArray:
                if (_verifyStartArray)
                {
                    if (reader.Read() == false)
                    {
                        return(false);
                    }

                    _verifyStartArray = false;

                    if (state.CurrentTokenType != JsonParserToken.StartArray)
                    {
                        ThrowInvalidReplicationHistoryType(state);
                    }
                }
                while (state.CurrentTokenType != JsonParserToken.EndArray)
                {
                    if (reader.Read() == false)
                    {
                        return(false);
                    }
                }
                break;

            case State.IgnoreRevisionStatusProperty:
                if (reader.Read() == false)
                {
                    return(false);
                }

                if (state.CurrentTokenType != JsonParserToken.String &&
                    state.CurrentTokenType != JsonParserToken.Integer)
                {
                    ThrowInvalidEtagType(state);
                }

                switch (CreateLazyStringValueFromParserState(state))
                {
                case LegacyHasRevisionsDocumentState:
                    NonPersistentFlags |= NonPersistentDocumentFlags.LegacyHasRevisions;
                    break;

                case LegacyRevisionState:
                    NonPersistentFlags |= NonPersistentDocumentFlags.LegacyRevision;
                    break;
                }
                break;

            case State.ReadingId:
                if (reader.Read() == false)
                {
                    return(false);
                }

                if (state.CurrentTokenType != JsonParserToken.String)
                {
                    ThrowExpectedFieldTypeOfString(Constants.Documents.Metadata.Id, state);
                }
                Id = CreateLazyStringValueFromParserState(state);
                break;

            case State.ReadingFlags:
                if (reader.Read() == false)
                {
                    return(false);
                }

                if (state.CurrentTokenType != JsonParserToken.String)
                {
                    ThrowExpectedFieldTypeOfString(Constants.Documents.Metadata.Flags, state);
                }
                Flags = ReadFlags(state);
                break;

            case State.ReadingChangeVector:
                if (reader.Read() == false)
                {
                    return(false);
                }

                if (state.CurrentTokenType != JsonParserToken.String)
                {
                    ThrowExpectedFieldTypeOfString(Constants.Documents.Metadata.ChangeVector, state);
                }
                ChangeVector = CreateLazyStringValueFromParserState(state);

                break;

            case State.ReadingFirstEtagOfLegacyRevision:
                if (reader.Read() == false)
                {
                    return(false);
                }

                if (state.CurrentTokenType != JsonParserToken.String)
                {
                    ThrowExpectedFieldTypeOfString("@etag", state);
                }
                _firstEtagOfLegacyRevision = CreateLazyStringValueFromParserState(state);
                ChangeVector = ChangeVectorUtils.NewChangeVector("RV", ++_legacyRevisionsCount, new Guid(_firstEtagOfLegacyRevision));

                break;
            }
            return(true);
        }
Example #6
0
        private unsafe bool AboutToReadPropertyNameInMetadataUnlikely(IJsonParser reader, JsonParserState state, out bool aboutToReadPropertyName)
        {
            aboutToReadPropertyName = true;

            switch (state.StringSize)
            {
            default:     // accept this property
            {
                return(true);
            }

            case -1:     // IgnoreProperty
            {
                if (reader.Read() == false)
                {
                    _state = State.IgnoreProperty;
                    {
                        aboutToReadPropertyName = false;
                        return(true);
                    }
                }
                if (state.CurrentTokenType == JsonParserToken.StartArray ||
                    state.CurrentTokenType == JsonParserToken.StartObject)
                {
                    ThrowInvalidMetadataProperty(state);
                }
                break;
            }

            case 3:     // @id
                if (state.StringBuffer[0] != (byte)'@' ||
                    *(short *)(state.StringBuffer + 1) != 25705)
                {
                    aboutToReadPropertyName = true;
                    return(true);
                }

                if (reader.Read() == false)
                {
                    _state = State.ReadingId;
                    {
                        aboutToReadPropertyName = false;
                        return(true);
                    }
                }
                if (state.CurrentTokenType != JsonParserToken.String)
                {
                    ThrowExpectedFieldTypeOfString(Constants.Documents.Metadata.Id, state);
                }
                Id = CreateLazyStringValueFromParserState(state);
                break;

            case 5:     // @etag
                if (state.StringBuffer[0] != (byte)'@' ||
                    *(int *)(state.StringBuffer + 1) != 1734440037)
                {
                    aboutToReadPropertyName = true;
                    return(true);
                }

                if (ReadFirstEtagOfLegacyRevision &&
                    (NonPersistentFlags & NonPersistentDocumentFlags.LegacyRevision) == NonPersistentDocumentFlags.LegacyRevision)
                {
                    if (_firstEtagOfLegacyRevision == null)
                    {
                        if (reader.Read() == false)
                        {
                            _state = State.ReadingFirstEtagOfLegacyRevision;
                            {
                                aboutToReadPropertyName = false;
                                return(true);
                            }
                        }
                        if (state.CurrentTokenType != JsonParserToken.String)
                        {
                            ThrowExpectedFieldTypeOfString("@etag", state);
                        }
                        _firstEtagOfLegacyRevision = CreateLazyStringValueFromParserState(state);
                        ChangeVector = ChangeVectorUtils.NewChangeVector("RV", ++_legacyRevisionsCount, new Guid(_firstEtagOfLegacyRevision));
                        break;
                    }

                    ChangeVector = ChangeVectorUtils.NewChangeVector("RV", ++_legacyRevisionsCount, new Guid(_firstEtagOfLegacyRevision));
                }

                goto case -1;

            case 6:     // @flags
                if (state.StringBuffer[0] != (byte)'@' ||
                    *(int *)(state.StringBuffer + 1) != 1734437990 ||
                    state.StringBuffer[1 + sizeof(int)] != (byte)'s')
                {
                    aboutToReadPropertyName = true;
                    return(true);
                }

                if (reader.Read() == false)
                {
                    _state = State.ReadingFlags;
                    {
                        aboutToReadPropertyName = false;
                        return(true);
                    }
                }
                if (state.CurrentTokenType != JsonParserToken.String)
                {
                    ThrowExpectedFieldTypeOfString(Constants.Documents.Metadata.Flags, state);
                }
                Flags = ReadFlags(state);
                break;

            case 12:     // @index-score
                if (state.StringBuffer[0] != (byte)'@' ||
                    *(long *)(state.StringBuffer + 1) != 7166121427196997225 ||
                    *(short *)(state.StringBuffer + 1 + sizeof(long)) != 29295 ||
                    state.StringBuffer[1 + sizeof(long) + sizeof(short)] != (byte)'e')
                {
                    aboutToReadPropertyName = true;
                    return(true);
                }

                goto case -1;

            case 13:     //Last-Modified
                if (*(long *)state.StringBuffer != 7237087983830262092 ||
                    *(int *)(state.StringBuffer + sizeof(long)) != 1701406313 ||
                    state.StringBuffer[12] != (byte)'d')
                {
                    aboutToReadPropertyName = true;
                    return(true);
                }

                goto case -1;

            case 14:
                if (state.StringBuffer[0] == (byte)'@')
                {
                    // @change-vector
                    if (*(long *)(state.StringBuffer + 1) == 8515573965335390307 &&
                        *(int *)(state.StringBuffer + 1 + sizeof(long)) == 1869898597 &&
                        state.StringBuffer[1 + sizeof(long) + sizeof(int)] == (byte)'r')
                    {
                        if (reader.Read() == false)
                        {
                            _state = State.ReadingChangeVector;
                            {
                                aboutToReadPropertyName = false;
                                return(true);
                            }
                        }
                        if (state.CurrentTokenType != JsonParserToken.String)
                        {
                            ThrowExpectedFieldTypeOfString(Constants.Documents.Metadata.ChangeVector, state);
                        }
                        ChangeVector = CreateLazyStringValueFromParserState(state);
                        break;
                    }

                    // @last-modified
                    if (*(long *)(state.StringBuffer + 1) == 7237123168202350956 &&
                        *(int *)(state.StringBuffer + 1 + sizeof(long)) == 1701406313 &&
                        state.StringBuffer[1 + sizeof(long) + sizeof(int)] == (byte)'d')
                    {
                        goto case -1;
                    }
                }

                {
                    aboutToReadPropertyName = true;
                    return(true);
                }

            case 15:     //Raven-Read-Only
                if (*(long *)state.StringBuffer != 7300947898092904786 ||
                    *(int *)(state.StringBuffer + sizeof(long)) != 1328374881 ||
                    *(short *)(state.StringBuffer + sizeof(long) + sizeof(int)) != 27758 ||
                    state.StringBuffer[14] != (byte)'y')
                {
                    aboutToReadPropertyName = true;
                    return(true);
                }

                goto case -1;

            case 17:     //Raven-Entity-Name --> @collection
                if (*(long *)state.StringBuffer != 7945807069737017682 ||
                    *(long *)(state.StringBuffer + sizeof(long)) != 7881666780093245812 ||
                    state.StringBuffer[16] != (byte)'e')
                {
                    aboutToReadPropertyName = true;
                    return(true);
                }

                var collection = _metadataCollections;
                state.StringBuffer = collection.AllocatedMemoryData.Address;
                state.StringSize   = collection.Size;
                {
                    aboutToReadPropertyName = true;
                    return(true);
                }

            case 19:     //Raven-Last-Modified
                if (*(long *)state.StringBuffer != 7011028672080929106 ||
                    *(long *)(state.StringBuffer + sizeof(long)) != 7379539893622240371 ||
                    *(short *)(state.StringBuffer + sizeof(long) + sizeof(long)) != 25961 ||
                    state.StringBuffer[18] != (byte)'d')
                {
                    aboutToReadPropertyName = true;
                    return(true);
                }

                goto case -1;

            case 21:     //Raven-Expiration-Date
                if (*(long *)state.StringBuffer != 8666383010116297042 ||
                    *(long *)(state.StringBuffer + sizeof(long)) != 7957695015158966640 ||
                    *(short *)(state.StringBuffer + sizeof(long) + sizeof(long)) != 17453 ||
                    state.StringBuffer[20] != (byte)'e')
                {
                    aboutToReadPropertyName = true;
                    return(true);
                }

                var expires = _metadataExpires;
                state.StringBuffer = expires.AllocatedMemoryData.Address;
                state.StringSize   = expires.Size;
                {
                    aboutToReadPropertyName = true;
                    return(true);
                }

            case 23:     //Raven-Document-Revision
                if (*(long *)state.StringBuffer != 8017583188798234962 ||
                    *(long *)(state.StringBuffer + sizeof(long)) != 5921517102558967139 ||
                    *(int *)(state.StringBuffer + sizeof(long) + sizeof(long)) != 1936291429 ||
                    *(short *)(state.StringBuffer + sizeof(long) + sizeof(long) + sizeof(int)) != 28521 ||
                    state.StringBuffer[22] != (byte)'n')
                {
                    aboutToReadPropertyName = true;
                    return(true);
                }

                goto case -1;

            case 24:     //Raven-Replication-Source
                if (*(long *)state.StringBuffer != 7300947898092904786 ||
                    *(long *)(state.StringBuffer + sizeof(long)) != 8028075772393122928 ||
                    *(long *)(state.StringBuffer + sizeof(long) + sizeof(long)) != 7305808869229538670)
                {
                    aboutToReadPropertyName = true;
                    return(true);
                }

                goto case -1;

            case 25:     //Raven-Replication-Version OR Raven-Replication-History
                if (*(long *)state.StringBuffer != 7300947898092904786 ||
                    *(long *)(state.StringBuffer + sizeof(long)) != 8028075772393122928)
                {
                    aboutToReadPropertyName = true;
                    return(true);
                }

                var value    = *(long *)(state.StringBuffer + sizeof(long) + sizeof(long));
                var lastByte = state.StringBuffer[24];
                if ((value != 8028074745928232302 || lastByte != (byte)'n') &&
                    (value != 8245937481775066478 || lastByte != (byte)'y'))
                {
                    aboutToReadPropertyName = true;
                    return(true);
                }

                var isReplicationHistory = lastByte == (byte)'y';
                if (reader.Read() == false)
                {
                    _verifyStartArray = isReplicationHistory;
                    _state            = isReplicationHistory ? State.IgnoreArray : State.IgnoreProperty;
                    {
                        aboutToReadPropertyName = false;
                        return(true);
                    }
                }

                // Raven-Replication-History is an array
                if (isReplicationHistory)
                {
                    if (state.CurrentTokenType != JsonParserToken.StartArray)
                    {
                        ThrowInvalidReplicationHistoryType(state);
                    }

                    do
                    {
                        if (reader.Read() == false)
                        {
                            _state = State.IgnoreArray;
                            {
                                aboutToReadPropertyName = false;
                                return(true);
                            }
                        }
                    } while (state.CurrentTokenType != JsonParserToken.EndArray);
                }
                else if (state.CurrentTokenType == JsonParserToken.StartArray ||
                         state.CurrentTokenType == JsonParserToken.StartObject)
                {
                    ThrowInvalidMetadataProperty(state);
                }
                break;

            case 29:     //Non-Authoritative-Information
                if (*(long *)state.StringBuffer != 7526769800038477646 ||
                    *(long *)(state.StringBuffer + sizeof(long)) != 8532478930943832687 ||
                    *(long *)(state.StringBuffer + sizeof(long) + sizeof(long)) != 7886488383206796645 ||
                    *(int *)(state.StringBuffer + sizeof(long) + sizeof(long) + sizeof(long)) != 1869182049 ||
                    state.StringBuffer[28] != (byte)'n')
                {
                    aboutToReadPropertyName = true;
                    return(true);
                }

                goto case -1;

            case 30:     //Raven-Document-Parent-Revision OR Raven-Document-Revision-Status
                if (*(long *)state.StringBuffer != 8017583188798234962)
                {
                    aboutToReadPropertyName = true;
                    return(true);
                }

                if ((*(long *)(state.StringBuffer + sizeof(long)) != 5777401914483111267 ||
                     *(long *)(state.StringBuffer + sizeof(long) + sizeof(long)) != 7300947924012593761 ||
                     *(int *)(state.StringBuffer + sizeof(long) + sizeof(long) + sizeof(long)) != 1769171318 ||
                     *(short *)(state.StringBuffer + sizeof(long) + sizeof(long) + sizeof(long) + sizeof(int)) != 28271) &&
                    (*(long *)(state.StringBuffer + sizeof(long)) != 5921517102558967139 ||
                     *(long *)(state.StringBuffer + sizeof(long) + sizeof(long)) != 3273676477843469925 ||
                     *(int *)(state.StringBuffer + sizeof(long) + sizeof(long) + sizeof(long)) != 1952543827 ||
                     *(short *)(state.StringBuffer + sizeof(long) + sizeof(long) + sizeof(long) + sizeof(int)) != 29557))
                {
                    aboutToReadPropertyName = true;
                    return(true);
                }

                var isRevisionStatusProperty = state.StringBuffer[29] == 's';
                if (reader.Read() == false)
                {
                    _state = isRevisionStatusProperty ? State.IgnoreRevisionStatusProperty : State.IgnoreProperty;
                    {
                        aboutToReadPropertyName = false;
                        return(true);
                    }
                }

                if (state.CurrentTokenType == JsonParserToken.StartArray ||
                    state.CurrentTokenType == JsonParserToken.StartObject)
                {
                    ThrowInvalidMetadataProperty(state);
                }

                if (isRevisionStatusProperty)
                {
                    switch (CreateLazyStringValueFromParserState(state))
                    {
                    case LegacyHasRevisionsDocumentState:
                        NonPersistentFlags |= NonPersistentDocumentFlags.LegacyHasRevisions;
                        break;

                    case LegacyRevisionState:
                        NonPersistentFlags |= NonPersistentDocumentFlags.LegacyRevision;
                        break;
                    }
                }

                break;

            case 32:     //Raven-Replication-Merged-History
                if (*(long *)state.StringBuffer != 7300947898092904786 ||
                    *(long *)(state.StringBuffer + sizeof(long)) != 8028075772393122928 ||
                    *(long *)(state.StringBuffer + sizeof(long) + sizeof(long)) != 7234302117464059246 ||
                    *(long *)(state.StringBuffer + sizeof(long) + sizeof(long) + sizeof(long)) != 8751179571877464109)
                {
                    aboutToReadPropertyName = true;
                    return(true);
                }

                goto case -1;
            }
            return(false);
        }
        private bool AboutToReadWithStateUnlikely(IJsonParser reader, JsonParserState state)
        {
            switch (_state)
            {
                case State.None:
                    break;
                case State.IgnoreProperty:
                    if (reader.Read() == false)
                        return false;

                    if (state.CurrentTokenType == JsonParserToken.StartArray ||
                        state.CurrentTokenType == JsonParserToken.StartObject)
                        ThrowInvalidMetadataProperty(state, reader);
                    break;
                case State.IgnoreArray:
                    if (_verifyStartArray)
                    {
                        if (reader.Read() == false)
                            return false;

                        _verifyStartArray = false;

                        if (state.CurrentTokenType != JsonParserToken.StartArray)
                            ThrowInvalidReplicationHistoryType(state, reader);
                    }
                    while (state.CurrentTokenType != JsonParserToken.EndArray)
                    {
                        if (reader.Read() == false)
                            return false;
                    }
                    break;
                case State.IgnoreRevisionStatusProperty:
                    if (reader.Read() == false)
                        return false;

                    if (state.CurrentTokenType != JsonParserToken.String &&
                        state.CurrentTokenType != JsonParserToken.Integer)
                        ThrowInvalidEtagType(state, reader);

                    switch (CreateLazyStringValueFromParserState(state))
                    {
                        case LegacyHasRevisionsDocumentState:
                            NonPersistentFlags |= NonPersistentDocumentFlags.LegacyHasRevisions;
                            break;
                        case LegacyRevisionState:
                            NonPersistentFlags |= NonPersistentDocumentFlags.LegacyRevision;
                            break;
                    }
                    break;
                case State.ReadingId:
                    if (reader.Read() == false)
                        return false;

                    if (state.CurrentTokenType != JsonParserToken.String)
                        ThrowExpectedFieldTypeOfString(Constants.Documents.Metadata.Id, state, reader);
                    Id = CreateLazyStringValueFromParserState(state);
                    break;
                case State.ReadingFlags:
                    if (reader.Read() == false)
                        return false;

                    if (state.CurrentTokenType != JsonParserToken.String)
                        ThrowExpectedFieldTypeOfString(Constants.Documents.Metadata.Flags, state, reader);
                    Flags = ReadFlags(state);
                    break;
                case State.ReadingLastModified:
                case State.ReadingLegacyLastModified:
                    if (reader.Read() == false)
                        return false;

                    if (state.CurrentTokenType != JsonParserToken.String)
                        ThrowExpectedFieldTypeOfString(Constants.Documents.Metadata.LastModified, state, reader);
                    LastModified = ReadDateTime(state, reader, _state);
                    break;
                case State.ReadingLegacyDeleteMarker:
                    if (reader.Read() == false)
                        return false;

                    if (state.CurrentTokenType == JsonParserToken.True)
                        NonPersistentFlags |= NonPersistentDocumentFlags.LegacyDeleteMarker;

                    break;
                case State.ReadingChangeVector:
                    if (reader.Read() == false)
                        return false;

                    if (state.CurrentTokenType != JsonParserToken.String)
                        ThrowExpectedFieldTypeOfString(Constants.Documents.Metadata.ChangeVector, state, reader);
                    ChangeVector = CreateLazyStringValueFromParserState(state);

                    break;
                case State.ReadingFirstEtagOfLegacyRevision:
                    if (reader.Read() == false)
                        return false;

                    if (state.CurrentTokenType != JsonParserToken.String)
                        ThrowExpectedFieldTypeOfString("@etag", state, reader);
                    FirstEtagOfLegacyRevision = LegacyEtag = CreateLazyStringValueFromParserState(state);
                    ChangeVector = ChangeVectorUtils.NewChangeVector("RV", ++LegacyRevisionsCount, new Guid(FirstEtagOfLegacyRevision).ToBase64Unpadded());
                    break;
                case State.ReadingEtag:
                    if (reader.Read() == false)
                        return false;

                    if (state.CurrentTokenType != JsonParserToken.String)
                        ThrowExpectedFieldTypeOfString("@etag", state, reader);
                    LegacyEtag = CreateLazyStringValueFromParserState(state);

                    break;
            }
            return true;
        }
        private unsafe bool AboutToReadPropertyNameInMetadataUnlikely(IJsonParser reader, JsonParserState state, out bool aboutToReadPropertyName)
        {
            aboutToReadPropertyName = true;

            switch (state.StringSize)
            {
                default: // accept this property
                    {
                        return true;
                    }
                case -2: // IgnoreArrayProperty
                    {
                        if (state.CurrentTokenType != JsonParserToken.StartArray)
                            ThrowInvalidArrayType(state, reader);

                        while (state.CurrentTokenType != JsonParserToken.EndArray)
                        {
                            if (reader.Read() == false)
                            {
                                _state = State.IgnoreArray;
                                aboutToReadPropertyName = false;
                                return true;
                            }
                        }
                        break;
                    }
                case -1: // IgnoreProperty
                    {
                        if (reader.Read() == false)
                        {
                            _state = State.IgnoreProperty;
                            aboutToReadPropertyName = false;
                            return true;
                        }
                        if (state.CurrentTokenType == JsonParserToken.StartArray ||
                            state.CurrentTokenType == JsonParserToken.StartObject)
                            ThrowInvalidMetadataProperty(state, reader);
                        break;
                    }

                case 3: // @id
                    if (state.StringBuffer[0] != (byte)'@' ||
                        *(short*)(state.StringBuffer + 1) != 25705)
                    {
                        aboutToReadPropertyName = true;
                        return true;
                    }

                    if (reader.Read() == false)
                    {
                        _state = State.ReadingId;
                        aboutToReadPropertyName = false;
                        return true;
                    }
                    if (state.CurrentTokenType != JsonParserToken.String)
                        ThrowExpectedFieldTypeOfString(Constants.Documents.Metadata.Id, state, reader);
                    Id = CreateLazyStringValueFromParserState(state);
                    break;
                case 5: // @etag
                    if (state.StringBuffer[0] != (byte)'@' ||
                        *(int*)(state.StringBuffer + 1) != 1734440037)
                    {
                        aboutToReadPropertyName = true;
                        return true;
                    }

                    if (ReadFirstEtagOfLegacyRevision &&
                        (NonPersistentFlags & NonPersistentDocumentFlags.LegacyRevision) == NonPersistentDocumentFlags.LegacyRevision)
                    {
                        if (FirstEtagOfLegacyRevision == null)
                        {
                            if (reader.Read() == false)
                            {
                                _state = State.ReadingFirstEtagOfLegacyRevision;
                                aboutToReadPropertyName = false;
                                return true;
                            }
                            if (state.CurrentTokenType != JsonParserToken.String)
                                ThrowExpectedFieldTypeOfString("@etag", state, reader);
                            FirstEtagOfLegacyRevision = LegacyEtag = CreateLazyStringValueFromParserState(state);
                            ChangeVector = ChangeVectorUtils.NewChangeVector("RV", ++LegacyRevisionsCount, new Guid(FirstEtagOfLegacyRevision).ToBase64Unpadded());
                            break;
                        }

                        ChangeVector = ChangeVectorUtils.NewChangeVector("RV", ++LegacyRevisionsCount, new Guid(FirstEtagOfLegacyRevision).ToBase64Unpadded());
                    }

                    if (ReadLegacyEtag)
                    {
                        if (reader.Read() == false)
                        {
                            _state = State.ReadingEtag;
                            aboutToReadPropertyName = false;
                            return true;
                        }

                        if (state.CurrentTokenType != JsonParserToken.String)
                            ThrowExpectedFieldTypeOfString("@etag", state, reader);
                        LegacyEtag = CreateLazyStringValueFromParserState(state);
                        break;
                    }

                    goto case -1;
                case 6: // @flags
                    if (state.StringBuffer[0] != (byte)'@' ||
                        *(int*)(state.StringBuffer + 1) != 1734437990 ||
                        state.StringBuffer[1 + sizeof(int)] != (byte)'s')
                    {
                        aboutToReadPropertyName = true;
                        return true;
                    }

                    if (reader.Read() == false)
                    {
                        _state = State.ReadingFlags;
                        aboutToReadPropertyName = false;
                        return true;
                    }
                    if (state.CurrentTokenType != JsonParserToken.String)
                        ThrowExpectedFieldTypeOfString(Constants.Documents.Metadata.Flags, state, reader);
                    Flags = ReadFlags(state);
                    break;

                case 9: // @counters
                    // always remove the @counters metadata
                    // not doing so might cause us to have counter on the document but not in the storage.
                    // the counters will be updated when we import the counters themselves
                    if (state.StringBuffer[0] != (byte)'@' ||
                        *(long*)(state.StringBuffer + 1) != 8318823012450529123)
                    {
                        aboutToReadPropertyName = true;
                        return true;
                    }

                    SeenCounters = true;
                    if (reader.Read() == false)
                    {
                        _verifyStartArray = true;
                        _state = State.IgnoreArray;
                        aboutToReadPropertyName = false;
                        return true;
                    }
                    goto case -2;

                case 12: // @index-score OR @attachments

                    if (state.StringBuffer[0] == (byte)'@')
                    {   // @index-score
                        if (*(long*)(state.StringBuffer + 1) == 7166121427196997225 &&
                            *(short*)(state.StringBuffer + 1 + sizeof(long)) == 29295 &&
                            state.StringBuffer[1 + sizeof(long) + sizeof(short)] == (byte)'e')
                        {
                            goto case -1;
                        }

                        // @attachments
                        SeenAttachments = true;
                        if (OperateOnTypes.HasFlag(DatabaseItemType.Attachments) == false &&
                            *(long*)(state.StringBuffer + 1) == 7308612546338255969 &&
                            *(short*)(state.StringBuffer + 1 + sizeof(long)) == 29806 &&
                            state.StringBuffer[1 + sizeof(long) + sizeof(short)] == (byte)'s')
                        {
                            if (reader.Read() == false)
                            {
                                _verifyStartArray = true;
                                _state = State.IgnoreArray;
                                aboutToReadPropertyName = false;
                                return true;
                            }
                            goto case -2;
                        }
                    }

                    aboutToReadPropertyName = true;
                    return true;
                case 13: //Last-Modified
                    if (*(long*)state.StringBuffer != 7237087983830262092 ||
                        *(int*)(state.StringBuffer + sizeof(long)) != 1701406313 ||
                        state.StringBuffer[12] != (byte)'d')
                    {
                        aboutToReadPropertyName = true;
                        return true;
                    }

                    goto case -1;

                case 14:
                    if (state.StringBuffer[0] == (byte)'@')
                    {
                        // @change-vector
                        if (*(long*)(state.StringBuffer + 1) == 8515573965335390307 &&
                            *(int*)(state.StringBuffer + 1 + sizeof(long)) == 1869898597 &&
                            state.StringBuffer[1 + sizeof(long) + sizeof(int)] == (byte)'r')
                        {
                            if (reader.Read() == false)
                            {
                                _state = State.ReadingChangeVector;
                                aboutToReadPropertyName = false;
                                return true;
                            }
                            if (state.CurrentTokenType != JsonParserToken.String)
                                ThrowExpectedFieldTypeOfString(Constants.Documents.Metadata.ChangeVector, state, reader);
                            ChangeVector = CreateLazyStringValueFromParserState(state);
                            break;
                        }

                        // @last-modified
                        if (*(long*)(state.StringBuffer + 1) == 7237123168202350956 &&
                            *(int*)(state.StringBuffer + 1 + sizeof(long)) == 1701406313 &&
                            state.StringBuffer[1 + sizeof(long) + sizeof(int)] == (byte)'d')
                        {
                            if (reader.Read() == false)
                            {
                                _state = State.ReadingLastModified;
                                aboutToReadPropertyName = false;
                                return true;
                            }
                            if (state.CurrentTokenType != JsonParserToken.String)
                                ThrowExpectedFieldTypeOfString(Constants.Documents.Metadata.LastModified, state, reader);
                            LastModified = ReadDateTime(state, reader, State.ReadingLastModified);
                            break;
                        }
                    }

                    aboutToReadPropertyName = true;
                    return true;
                case 15: //Raven-Read-Only
                    if (*(long*)state.StringBuffer != 7300947898092904786 ||
                        *(int*)(state.StringBuffer + sizeof(long)) != 1328374881 ||
                        *(short*)(state.StringBuffer + sizeof(long) + sizeof(int)) != 27758 ||
                        state.StringBuffer[14] != (byte)'y')
                    {
                        aboutToReadPropertyName = true;
                        return true;
                    }

                    goto case -1;

                case 17: //Raven-Entity-Name --> @collection
                    if (*(long*)state.StringBuffer != 7945807069737017682 ||
                        *(long*)(state.StringBuffer + sizeof(long)) != 7881666780093245812 ||
                        state.StringBuffer[16] != (byte)'e')
                    {
                        aboutToReadPropertyName = true;
                        return true;
                    }

                    var collection = _metadataCollections;
                    state.StringBuffer = collection.AllocatedMemoryData.Address;
                    state.StringSize = collection.Size;
                    aboutToReadPropertyName = true;
                    return true;
                case 19: //Raven-Last-Modified or Raven-Delete-Marker
                    if (*(int*)state.StringBuffer != 1702256978 ||
                        *(short*)(state.StringBuffer + sizeof(int)) != 11630)
                    {
                        aboutToReadPropertyName = true;
                        return true;
                    }

                    var longValue = *(long*)(state.StringBuffer + sizeof(int) + sizeof(short));
                    var intValue = *(int*)(state.StringBuffer + sizeof(int) + sizeof(short) + sizeof(long));
                    if ((longValue != 7237087983830262092 || intValue != 1701406313) && // long: Last-Mod, int: ifie
                        (longValue != 5561212665464644932 || intValue != 1701540449))   // long: Delete-M, int: arke
                    {
                        aboutToReadPropertyName = true;
                        return true;
                    }

                    var lb = state.StringBuffer[18];
                    if (lb != (byte)'d' && lb != (byte)'r')
                    {
                        aboutToReadPropertyName = true;
                        return true;
                    }

                    var isLegacyLastModified = lb == (byte)'d';
                    if (reader.Read() == false)
                    {
                        _state = isLegacyLastModified ? State.ReadingLegacyLastModified : State.ReadingLegacyDeleteMarker;
                        aboutToReadPropertyName = false;
                        return true;
                    }

                    if (isLegacyLastModified)
                    {
                        if (state.CurrentTokenType != JsonParserToken.String)
                            ThrowExpectedFieldTypeOfString(LegacyLastModified, state, reader);

                        LastModified = ReadDateTime(state, reader, State.ReadingLegacyLastModified);
                    }
                    else
                    {
                        if (state.CurrentTokenType == JsonParserToken.True)
                            NonPersistentFlags |= NonPersistentDocumentFlags.LegacyDeleteMarker;
                    }

                    break;
                case 21: //Raven-Expiration-Date
                    if (*(long*)state.StringBuffer != 8666383010116297042 ||
                        *(long*)(state.StringBuffer + sizeof(long)) != 7957695015158966640 ||
                        *(short*)(state.StringBuffer + sizeof(long) + sizeof(long)) != 17453 ||
                        state.StringBuffer[20] != (byte)'e')
                    {
                        aboutToReadPropertyName = true;
                        return true;
                    }

                    var expires = _metadataExpires;
                    state.StringBuffer = expires.AllocatedMemoryData.Address;
                    state.StringSize = expires.Size;
                    aboutToReadPropertyName = true;
                    return true;
                case 23: //Raven-Document-Revision
                    if (*(long*)state.StringBuffer != 8017583188798234962 ||
                        *(long*)(state.StringBuffer + sizeof(long)) != 5921517102558967139 ||
                        *(int*)(state.StringBuffer + sizeof(long) + sizeof(long)) != 1936291429 ||
                        *(short*)(state.StringBuffer + sizeof(long) + sizeof(long) + sizeof(int)) != 28521 ||
                        state.StringBuffer[22] != (byte)'n')
                    {
                        aboutToReadPropertyName = true;
                        return true;
                    }

                    goto case -1;
                case 24: //Raven-Replication-Source
                    if (*(long*)state.StringBuffer != 7300947898092904786 ||
                        *(long*)(state.StringBuffer + sizeof(long)) != 8028075772393122928 ||
                        *(long*)(state.StringBuffer + sizeof(long) + sizeof(long)) != 7305808869229538670)
                    {
                        aboutToReadPropertyName = true;
                        return true;
                    }

                    goto case -1;
                case 25: //Raven-Replication-Version OR Raven-Replication-History
                    if (*(long*)state.StringBuffer != 7300947898092904786 ||
                        *(long*)(state.StringBuffer + sizeof(long)) != 8028075772393122928)
                    {
                        aboutToReadPropertyName = true;
                        return true;
                    }

                    var value = *(long*)(state.StringBuffer + sizeof(long) + sizeof(long));
                    var lastByte = state.StringBuffer[24];
                    if ((value != 8028074745928232302 || lastByte != (byte)'n') &&
                        (value != 8245937481775066478 || lastByte != (byte)'y'))
                    {
                        aboutToReadPropertyName = true;
                        return true;
                    }

                    var isReplicationHistory = lastByte == (byte)'y';
                    if (reader.Read() == false)
                    {
                        _verifyStartArray = isReplicationHistory;
                        _state = isReplicationHistory ? State.IgnoreArray : State.IgnoreProperty;
                        aboutToReadPropertyName = false;
                        return true;
                    }

                    // Raven-Replication-History is an array
                    if (isReplicationHistory)
                    {
                        goto case -2;
                    }
                    else if (state.CurrentTokenType == JsonParserToken.StartArray ||
                             state.CurrentTokenType == JsonParserToken.StartObject)
                        ThrowInvalidMetadataProperty(state, reader);
                    break;
                case 29: //Non-Authoritative-Information
                    if (*(long*)state.StringBuffer != 7526769800038477646 ||
                        *(long*)(state.StringBuffer + sizeof(long)) != 8532478930943832687 ||
                        *(long*)(state.StringBuffer + sizeof(long) + sizeof(long)) != 7886488383206796645 ||
                        *(int*)(state.StringBuffer + sizeof(long) + sizeof(long) + sizeof(long)) != 1869182049 ||
                        state.StringBuffer[28] != (byte)'n')
                    {
                        aboutToReadPropertyName = true;
                        return true;
                    }

                    goto case -1;

                case 30: //Raven-Document-Parent-Revision OR Raven-Document-Revision-Status
                    if (*(long*)state.StringBuffer != 8017583188798234962)
                    {
                        aboutToReadPropertyName = true;
                        return true;
                    }

                    if ((*(long*)(state.StringBuffer + sizeof(long)) != 5777401914483111267 ||
                         *(long*)(state.StringBuffer + sizeof(long) + sizeof(long)) != 7300947924012593761 ||
                         *(int*)(state.StringBuffer + sizeof(long) + sizeof(long) + sizeof(long)) != 1769171318 ||
                         *(short*)(state.StringBuffer + sizeof(long) + sizeof(long) + sizeof(long) + sizeof(int)) != 28271) &&
                        (*(long*)(state.StringBuffer + sizeof(long)) != 5921517102558967139 ||
                         *(long*)(state.StringBuffer + sizeof(long) + sizeof(long)) != 3273676477843469925 ||
                         *(int*)(state.StringBuffer + sizeof(long) + sizeof(long) + sizeof(long)) != 1952543827 ||
                         *(short*)(state.StringBuffer + sizeof(long) + sizeof(long) + sizeof(long) + sizeof(int)) != 29557))
                    {
                        aboutToReadPropertyName = true;
                        return true;
                    }

                    var isRevisionStatusProperty = state.StringBuffer[29] == 's';
                    if (reader.Read() == false)
                    {
                        _state = isRevisionStatusProperty ? State.IgnoreRevisionStatusProperty : State.IgnoreProperty;
                        aboutToReadPropertyName = false;
                        return true;
                    }

                    if (state.CurrentTokenType == JsonParserToken.StartArray ||
                        state.CurrentTokenType == JsonParserToken.StartObject)
                        ThrowInvalidMetadataProperty(state, reader);

                    if (isRevisionStatusProperty)
                    {
                        switch (CreateLazyStringValueFromParserState(state))
                        {
                            case LegacyHasRevisionsDocumentState:
                                NonPersistentFlags |= NonPersistentDocumentFlags.LegacyHasRevisions;
                                break;
                            case LegacyRevisionState:
                                NonPersistentFlags |= NonPersistentDocumentFlags.LegacyRevision;
                                break;
                        }
                    }

                    break;
                case 32: //Raven-Replication-Merged-History
                    if (*(long*)state.StringBuffer != 7300947898092904786 ||
                        *(long*)(state.StringBuffer + sizeof(long)) != 8028075772393122928 ||
                        *(long*)(state.StringBuffer + sizeof(long) + sizeof(long)) != 7234302117464059246 ||
                        *(long*)(state.StringBuffer + sizeof(long) + sizeof(long) + sizeof(long)) != 8751179571877464109)
                    {
                        aboutToReadPropertyName = true;
                        return true;
                    }

                    goto case -1;
            }
            return false;
        }
Example #9
0
        public virtual bool Read()
        {
            if (_continuationState.Count == 0)
            {
                return(false); //nothing to do
            }
            var currentState = _continuationState.Pop();

            while (true)
            {
                switch (currentState.State)
                {
                case ContinuationState.ReadObjectDocument:
                    if (_reader.Read() == false)
                    {
                        _continuationState.Push(currentState);
                        return(false);
                    }
                    currentState.State = ContinuationState.ReadObject;
                    continue;

                case ContinuationState.ReadArrayDocument:
                    if (_reader.Read() == false)
                    {
                        _continuationState.Push(currentState);
                        return(false);
                    }

                    var fakeFieldName = _context.GetLazyStringForFieldWithCaching("_");
                    var propIndex     = _context.CachedProperties.GetPropertyId(fakeFieldName);
                    currentState.CurrentPropertyId = propIndex;
                    currentState.MaxPropertyId     = propIndex;
                    currentState.FirstWrite        = _writer.Position;
                    currentState.Properties        = new List <PropertyTag>
                    {
                        new PropertyTag
                        {
                            PropertyId = propIndex
                        }
                    };
                    currentState.State = ContinuationState.CompleteDocumentArray;
                    _continuationState.Push(currentState);
                    currentState = new BuildingState
                    {
                        State = ContinuationState.ReadArray
                    };
                    continue;

                case ContinuationState.CompleteDocumentArray:
                    currentState.Properties[0].Type     = (byte)_writeToken.WrittenToken;
                    currentState.Properties[0].Position = _writeToken.ValuePos;

                    // Register property position, name id (PropertyId) and type (object type and metadata)
                    _writeToken = _writer.WriteObjectMetadata(currentState.Properties, currentState.FirstWrite, currentState.MaxPropertyId);

                    return(true);

                case ContinuationState.ReadObject:
                    if (_state.CurrentTokenType != JsonParserToken.StartObject)
                    {
                        throw new InvalidDataException("Expected start of object, but got " + _state.CurrentTokenType);
                    }
                    currentState.State      = ContinuationState.ReadPropertyName;
                    currentState.Properties = new List <PropertyTag>();
                    currentState.FirstWrite = _writer.Position;
                    continue;

                case ContinuationState.ReadArray:
                    if (_state.CurrentTokenType != JsonParserToken.StartArray)
                    {
                        throw new InvalidDataException("Expected start of array, but got " + _state.CurrentTokenType);
                    }
                    currentState.Types     = new List <BlittableJsonToken>();
                    currentState.Positions = new List <int>();
                    currentState.State     = ContinuationState.ReadArrayValue;
                    continue;

                case ContinuationState.ReadArrayValue:
                    if (_reader.Read() == false)
                    {
                        _continuationState.Push(currentState);
                        return(false);
                    }
                    if (_state.CurrentTokenType == JsonParserToken.EndArray)
                    {
                        currentState.State = ContinuationState.CompleteArray;
                        continue;
                    }
                    currentState.State = ContinuationState.CompleteArrayValue;
                    _continuationState.Push(currentState);
                    currentState = new BuildingState
                    {
                        State = ContinuationState.ReadValue
                    };
                    continue;

                case ContinuationState.CompleteArrayValue:
                    currentState.Types.Add(_writeToken.WrittenToken);
                    currentState.Positions.Add(_writeToken.ValuePos);
                    currentState.State = ContinuationState.ReadArrayValue;
                    continue;

                case ContinuationState.CompleteArray:

                    var arrayToken     = BlittableJsonToken.StartArray;
                    var arrayInfoStart = _writer.WriteArrayMetadata(currentState.Positions, currentState.Types,
                                                                    ref arrayToken);

                    _writeToken = new WriteToken
                    {
                        ValuePos     = arrayInfoStart,
                        WrittenToken = arrayToken
                    };

                    currentState = _continuationState.Pop();
                    continue;

                case ContinuationState.ReadPropertyName:
                    if (_reader.Read() == false)
                    {
                        _continuationState.Push(currentState);
                        return(false);
                    }

                    if (_state.CurrentTokenType == JsonParserToken.EndObject)
                    {
                        _writeToken = _writer.WriteObjectMetadata(currentState.Properties, currentState.FirstWrite,
                                                                  currentState.MaxPropertyId);
                        if (_continuationState.Count == 0)
                        {
                            return(true);
                        }
                        currentState = _continuationState.Pop();
                        continue;
                    }

                    if (_state.CurrentTokenType != JsonParserToken.String)
                    {
                        throw new InvalidDataException("Expected property, but got " + _state.CurrentTokenType);
                    }


                    var property = CreateLazyStringValueFromParserState();

                    currentState.CurrentPropertyId = _context.CachedProperties.GetPropertyId(property);
                    currentState.MaxPropertyId     = Math.Max(currentState.MaxPropertyId, currentState.CurrentPropertyId);
                    currentState.State             = ContinuationState.ReadPropertyValue;
                    continue;

                case ContinuationState.ReadPropertyValue:
                    if (_reader.Read() == false)
                    {
                        _continuationState.Push(currentState);
                        return(false);
                    }
                    currentState.State = ContinuationState.CompleteReadingPropertyValue;
                    _continuationState.Push(currentState);
                    currentState = new BuildingState
                    {
                        State = ContinuationState.ReadValue
                    };
                    continue;

                case ContinuationState.CompleteReadingPropertyValue:
                    // Register property position, name id (PropertyId) and type (object type and metadata)
                    currentState.Properties.Add(new PropertyTag
                    {
                        Position   = _writeToken.ValuePos,
                        Type       = (byte)_writeToken.WrittenToken,
                        PropertyId = currentState.CurrentPropertyId
                    });
                    currentState.State = ContinuationState.ReadPropertyName;
                    continue;

                case ContinuationState.ReadValue:
                    ReadJsonValue();
                    currentState = _continuationState.Pop();
                    break;
                }
            }
        }