All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.amazon.ion.impl.IonReaderTreeUserX Maven / Gradle / Ivy

There is a newer version: 1.11.9
Show newest version
/*
 * Copyright 2007-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License").
 * You may not use this file except in compliance with the License.
 * A copy of the License is located at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * or in the "license" file accompanying this file. This file is distributed
 * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
 * express or implied. See the License for the specific language governing
 * permissions and limitations under the License.
 */

package com.amazon.ion.impl;

import static com.amazon.ion.SymbolTable.UNKNOWN_SYMBOL_ID;
import static com.amazon.ion.SystemSymbols.ION_1_0_SID;
import static com.amazon.ion.SystemSymbols.ION_SYMBOL_TABLE;

import com.amazon.ion.IonCatalog;
import com.amazon.ion.IonDatagram;
import com.amazon.ion.IonStruct;
import com.amazon.ion.IonSymbol;
import com.amazon.ion.IonType;
import com.amazon.ion.IonValue;
import com.amazon.ion.SeekableReader;
import com.amazon.ion.Span;
import com.amazon.ion.SpanProvider;
import com.amazon.ion.SymbolTable;


final class IonReaderTreeUserX
    extends IonReaderTreeSystem
    implements _Private_ReaderWriter
{

    private final _Private_LocalSymbolTableFactory _lstFactory;

    IonCatalog _catalog;
    private SymbolTable _symbols;

    public IonReaderTreeUserX(IonValue value, IonCatalog catalog, _Private_LocalSymbolTableFactory lstFactory)
    {
        super(value); // calls re_init
        _catalog = catalog;
        _lstFactory = lstFactory;
    }

    @Override
    void re_init(IonValue value, boolean hoisted)
    {
        super.re_init(value, hoisted);
        _symbols = _system_symtab;
    }

    //========================================================================

    @Override
    public SymbolTable getSymbolTable()
    {
        return _symbols;
    }

    @Override
    public boolean hasNext()
    {
        return next_helper_user();
    }

    @Override
    public IonType next()
    {
        if (!next_helper_user()) {
            this._curr = null;
            return null;
        }
        this._curr = this._next;
        this._next = null;
        return this._curr.getType();
    }

    boolean next_helper_user()
    {
        if (_eof) return false;
        if (_next != null) return true;

        clear_system_value_stack();

        // read values from the system
        // reader and if they are system values
        // process them.  Return when we've
        // read all the immediate system values
        IonType next_type;
        for (;;) {
            next_type = next_helper_system();

            if (_top == 0 && _parent instanceof IonDatagram) {
                if (IonType.SYMBOL.equals(next_type)) {
                    assert(_next instanceof IonSymbol);
                    IonSymbol sym = (IonSymbol)_next;
                    if (sym.isNullValue()) {
                        // there are no null values we will consume here
                        break;
                    }
                    int sid = sym.getSymbolId();
                    if (sid == UNKNOWN_SYMBOL_ID) {
                        String name = sym.stringValue();
                        if (name != null) {
                            sid = _system_symtab.findSymbol(name);
                        }
                    }
                    if (sid == ION_1_0_SID
                        && _next.getTypeAnnotationSymbols().length == 0) {
                        // $ion_1_0 is read as an IVM only if it is not annotated
                        SymbolTable symbols = _system_symtab;
                        _symbols = symbols;
                        push_symbol_table(symbols);
                        _next = null;
                        continue;
                    }
                }
                else if (IonType.STRUCT.equals(next_type)
                      && _next.findTypeAnnotation(ION_SYMBOL_TABLE) == 0
                ) {
                    assert(_next instanceof IonStruct);
                    // read a local symbol table
                    IonReaderTreeUserX reader = new IonReaderTreeUserX(_next, _catalog, _lstFactory);
                    // The child reader's symbol table is the symbol table that was active when the value began.
                    reader._symbols = _symbols;
                    SymbolTable symtab = _lstFactory.newLocalSymtab(_catalog, reader, false);
                    _symbols = symtab;
                    push_symbol_table(symtab);
                    _next = null;
                    continue;
                }
            }
            // if we get here we didn't process a system
            // value, if we had we would have 'continue'd
            // so this is a value the user gets
            break;
        }
        return (next_type != null);
    }
    //
    //  This code handles the skipped symbol table
    //  support - it is cloned in IonReaderTextUserX
    //  and IonReaderBinaryUserX
    //
    //  SO ANY FIXES HERE WILL BE NEEDED IN THOSE
    //  TWO LOCATIONS AS WELL.
    //
    private int _symbol_table_top = 0;
    private SymbolTable[] _symbol_table_stack = new SymbolTable[3]; // 3 is rare, IVM followed by a local sym tab with open content
    private void clear_system_value_stack()
    {
        while (_symbol_table_top > 0) {
            _symbol_table_top--;
            _symbol_table_stack[_symbol_table_top] = null;
        }
    }
    private void push_symbol_table(SymbolTable symbols)
    {
        assert(symbols != null);
        if (_symbol_table_top >= _symbol_table_stack.length) {
            int new_len = _symbol_table_stack.length * 2;
            SymbolTable[] temp = new SymbolTable[new_len];
            System.arraycopy(_symbol_table_stack, 0, temp, 0, _symbol_table_stack.length);
            _symbol_table_stack = temp;
        }
        _symbol_table_stack[_symbol_table_top++] = symbols;
    }
    public SymbolTable pop_passed_symbol_table()
    {
        if (_symbol_table_top <= 0) {
            return null;
        }
        _symbol_table_top--;
        SymbolTable symbols = _symbol_table_stack[_symbol_table_top];
        _symbol_table_stack[_symbol_table_top] = null;
        return symbols;
    }


    private static final class TreeSpan
        extends DowncastingFaceted
        implements Span
    {
        IonValue _value;
    }

    private final Span currentSpanImpl()
    {
        if (this._curr == null) {
            throw new IllegalStateException("Reader has no current value");
        }

        TreeSpan span = new TreeSpan();
        span._value = this._curr;

        return span;
    }


    private void hoistImpl(Span span)
    {
        if (span instanceof TreeSpan) {
            TreeSpan treeSpan = (TreeSpan)span;
            this.re_init(treeSpan._value, /* hoisted */ true);
        }
        else {
            // TODO custom exception
            throw new IllegalArgumentException("Span not appropriate for this reader");
        }
    }


    //========================================================================
    // Facet support


    @Override
    public  T asFacet(Class facetType)
    {
        if ((facetType == SeekableReader.class) ||
            (facetType == SpanProvider.class))
        {
            return facetType.cast(new SeekableReaderFacet());
        }

        return super.asFacet(facetType);
    }


    private class SeekableReaderFacet implements SeekableReader
    {
        public Span currentSpan()
        {
            return currentSpanImpl();
        }

        public void hoist(Span span)
        {
            hoistImpl(span);
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy