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

software.amazon.ion.impl.SymbolTableReader Maven / Gradle / Ivy

There is a newer version: 1.5.1
Show newest version
/*
 * Copyright 2011-2016 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://aws.amazon.com/apache2.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 software.amazon.ion.impl;


import static software.amazon.ion.SystemSymbols.IMPORTS;
import static software.amazon.ion.SystemSymbols.IMPORTS_SID;
import static software.amazon.ion.SystemSymbols.ION_SHARED_SYMBOL_TABLE;
import static software.amazon.ion.SystemSymbols.ION_SHARED_SYMBOL_TABLE_SID;
import static software.amazon.ion.SystemSymbols.ION_SYMBOL_TABLE;
import static software.amazon.ion.SystemSymbols.ION_SYMBOL_TABLE_SID;
import static software.amazon.ion.SystemSymbols.MAX_ID;
import static software.amazon.ion.SystemSymbols.MAX_ID_SID;
import static software.amazon.ion.SystemSymbols.NAME;
import static software.amazon.ion.SystemSymbols.NAME_SID;
import static software.amazon.ion.SystemSymbols.SYMBOLS;
import static software.amazon.ion.SystemSymbols.SYMBOLS_SID;
import static software.amazon.ion.SystemSymbols.VERSION;
import static software.amazon.ion.SystemSymbols.VERSION_SID;
import static software.amazon.ion.impl.PrivateUtils.newSymbolToken;

import java.io.IOException;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.Arrays;
import java.util.Date;
import java.util.Iterator;
import software.amazon.ion.Decimal;
import software.amazon.ion.IntegerSize;
import software.amazon.ion.IonException;
import software.amazon.ion.IonReader;
import software.amazon.ion.IonType;
import software.amazon.ion.SymbolTable;
import software.amazon.ion.SymbolToken;
import software.amazon.ion.Timestamp;

/**
 *   This is a reader that traverses a {@link SymbolTable}
 *   and returns the contents as if the table was serialized
 *   in Ion in a standard fashion (in fact this serialization
 *   defines the "standard fashion").
 *
 *   This does not support open content in symbol tables and
 *   should.  Support for open content will require additional
 *   data be kept in the {@link SymbolTable}, probably as an
 *   IonStruct or an IonReader or binary buffer.
 *
 *   The reader uses the _state member to track its progress
 *   through the members of the outer struct, the import
 *   list and the symbol list.  It used _idx to track its
 *   progress thought the elements of the import list and
 *   the elements of the symbol list.
 *
 *

    These are the states in a local symbol table:

        
        
        $ion_symbol_table:: {
          
          
            max_id:3,
          
            symbols:[
          
          
              "symbol1",
          
              "symbol2",
          
              "symbol3"
          
            ]
          
        }
        

    States for a shared symbol Table:

        
        
            $ion_shared_symbol_table::{
          
          
              name:"mySharedTable",
          
              version:1,
          
              max_id:3,
          
              imports:[
            
            
                {
              
              
                  name:"otherTable",
              
                  version:2,
              
                  max_id:192
              
                },
            
                {
              
              
                  name:"yetAnotherTable",
              
                  version:4,
              
                  max_id:34
              
                },
            
              ],
            new
          
              symbols:[
            
            
                "symbol1",
            
                "symbol2",
            
                "symbol3"
            
              ]
          
            }
        


        Version 1.0 system symbol table:

        
        
            $ion_symbol_table::{
        
        
              version:1,
        
              max_id:9,
        
              symbols:[
        
        
            "$ion",
        
            "$ion_1_0",
        
            "$ion_symbol_table",
        
            "name",
        
            "version",
        
            "imports",
        
            "symbols",
        
            "max_id",
        
            "$ion_shared_symbol_table"
        
              ]
        
            }
        

 */

/*  --------------------------------------------------------------------------------

Notes regarding the various states that may be encountered.
The reader depth is in parenthesis after the name

state                      next()                  stepIn()                stepOut()                     container
------------------------   ---------------------   ---------------------   -------------------------     ---------
S_BOF(0)                 = S_STRUCT              |                 |                     |           |

S_STRUCT(0)              = S_EOF                 | S_IN_STRUCT            |                     | true      |

S_IN_STRUCT(1)           = S_NAME (load)         |                 | S_EOF                      |           |
            [if no name] : S_VERSION (load)      |                 | S_EOF                      |           |
             [if no ver] : S_MAX_ID (load)       |                 | S_EOF                      |           |

S_NAME(1)                = S_VERSION (load)      |                 | S_EOF                      |           |
             [if no ver] : S_MAX_ID (load)       |                 | S_EOF                      |           |

S_VERSION(1)             = S_MAX_ID (load)       |                 | S_EOF                      |           |

S_MAX_ID(1)              = S_IMPORT_LIST (load)  |                 | S_EOF                      |           |
         [if no imports] : S_SYMBOL_LIST         |                 | S_EOF                      |           |
          [if no locals] : S_EOF                 |                 | S_EOF                      |           |

S_IMPORT_LIST(1)         = S_SYMBOL_LIST (load)  | S_IN_IMPORTS           | S_EOF                      | true      |
          [if no locals] : S_EOF                 |                 | S_EOF                      |           |

S_IN_IMPORTS(2)          = S_IMPORT_STRUCT       |                 | S_AFTER_IMPORT_LIST (load) |           |
    [if no more imports] : S_EOF                 |                 | S_AFTER_IMPORT_LIST (load) |           |
          [if no locals] : -------               | -------                | S_STRUCT_CLOSE             |           |

S_IMPORT_STRUCT(2)       = S_IMPORT_STRUCT       | S_IN_IMPORT_STRUCT     | S_AFTER_IMPORT_LIST (load) | true      |
    [if no more imports] : S_IMPORT_STRUCT_CLOSE |                 | S_AFTER_IMPORT_LIST (load) |           |
          [if no locals] : -------               | -------                | S_STRUCT_CLOSE             |           |

S_IN_IMPORT_STRUCT(3)    = S_IMPORT_NAME (load)  |                 | S_IMPORT_STRUCT            |           |
    [if no more imports] : -------               | -------                | S_IMPORT_STRUCT_CLOSE      |           |

S_IMPORT_NAME(3)         = S_IMPORT_VERSION(load)|                 | S_IMPORT_STRUCT            |           |
    [if no more imports] : -------               | -------                | S_IMPORT_STRUCT_CLOSE      |           |

S_IMPORT_VERSION(3)      = S_IMPORT_MAX_ID (load)|                 | S_IMPORT_STRUCT            |           |
    [if no more imports] : -------               | -------                | S_IMPORT_STRUCT_CLOSE      |           |

S_IMPORT_MAX_ID(3)       = S_IMPORT_STRUCT_CLOSE |                 | S_IMPORT_STRUCT            |           |
    [if no more imports] : -------               | -------                | S_IMPORT_STRUCT_CLOSE      |           |

S_IMPORT_STRUCT_CLOSE(3) = S_IMPORT_STRUCT_CLOSE |                 | S_IMPORT_STRUCT            |           |
    [if no more imports] : -------               | -------                | S_STRUCT_CLOSE             |           |

S_IMPORT_LIST_CLOSE(2)   = S_IMPORT_LIST_CLOSE   |                 | S_AFTER_IMPORT_LIST (load) |           |
          [if no locals] : S_IMPORT_LIST_CLOSE   |                 | S_STRUCT_CLOSE             |           |

S_AFTER_IMPORT_LIST(1)   = S_SYMBOL_LIST         |                 | S_EOF                      |           |

S_SYMBOL_LIST(1)         = S_STRUCT_CLOSE        | S_IN_SYMBOLS           | S_EOF                      | true      |
          [if no locals] : -------               | S_SYMBOL_LIST_CLOSE    | S_EOF                      |           |

S_IN_SYMBOLS(2)          = S_SYMBOL (load)       |                 | S_STRUCT_CLOSE             |           |
     [if no more locals] : S_SYMBOL_LIST_CLOSE   |                 | S_STRUCT_CLOSE             |           |

S_SYMBOL(2)              = S_SYMBOL (load)       |                 | S_STRUCT_CLOSE             |           |
     [if no more locals] : S_SYMBOL_LIST_CLOSE   |                 | S_STRUCT_CLOSE             |           |

S_SYMBOL_LIST_CLOSE(2)   = S_EOF                 |                 | S_STRUCT_CLOSE             |           |

S_STRUCT_CLOSE(1)        = S_EOF                 |                 | S_EOF                      |           |
S_EOF(0)                 = S_EOF                 |                 | S_EOF                      |           |


Same list sorted by depth (i.e. by the various sequences that
the reader progresses through to a local or global eof)

state
------------------------
S_BOF(0)                   system
S_STRUCT(0)                required
S_EOF(0)                   system


S_IN_STRUCT(1)             system
S_NAME(1)                  optional   if name not null (or if isLocalSymbolTable == false)
S_VERSION(1)               optional   if version > 0  (or if isLocalSymbolTable == false)
S_MAX_ID(1)                optional   if max_id > 0
S_IMPORT_LIST(1)           optional   if import count > 0
S_AFTER_IMPORT_LIST(1)     optional   if import count > 0 && local count > 0 (this state exists only after stepOut of the import list)
S_SYMBOL_LIST(1)           optional:  if local count > 0
S_STRUCT_CLOSE(1)          system


S_IN_IMPORTS(2)            system
S_IMPORT_STRUCT(2)         variable   if _imports.hasNext() (import symbol table iterator)
S_IMPORT_LIST_CLOSE(2)     system


S_IN_IMPORT_STRUCT(3)      system
S_IMPORT_NAME(3)           required
S_IMPORT_VERSION(3)        required
S_IMPORT_MAX_ID(3)         required
S_IMPORT_STRUCT_CLOSE(3)   system


S_IN_SYMBOLS(2)            system
S_SYMBOL(2)                variable  if _symbols.hasNext() (local symbol iterator)
S_SYMBOL_LIST_CLOSE(2)     system

*/


final class SymbolTableReader
    implements IonReader
{

    /**
     * these are the states of the reader.
     * Each state tells the reader it is
     * just before (or on as you might want
     * to think about it) one of the possible
     * values in the serialized image.
     */
    static final int S_BOF                  =  0;
    static final int S_STRUCT               =  1;
    static final int S_IN_STRUCT            =  2;
    static final int S_NAME                 =  3;
    static final int S_VERSION              =  4;
    static final int S_MAX_ID               =  5;
    static final int S_IMPORT_LIST          =  6;
    static final int S_IN_IMPORTS           =  7;
    static final int S_IMPORT_STRUCT        =  8;
    static final int S_IN_IMPORT_STRUCT     =  9;
    static final int S_IMPORT_NAME          = 10;
    static final int S_IMPORT_VERSION       = 11;
    static final int S_IMPORT_MAX_ID        = 12;
    static final int S_IMPORT_STRUCT_CLOSE  = 13;
    static final int S_IMPORT_LIST_CLOSE    = 14;
    static final int S_AFTER_IMPORT_LIST    = 15;
    static final int S_SYMBOL_LIST          = 16;
    static final int S_IN_SYMBOLS           = 17;
    static final int S_SYMBOL               = 18;
    static final int S_SYMBOL_LIST_CLOSE    = 19;
    static final int S_STRUCT_CLOSE         = 20;
    static final int S_EOF                  = 21;

    private final static String get_state_name(int state)
    {
        switch (state) {
        case S_BOF:                     return "S_BOF";
        case S_STRUCT:                  return "S_STRUCT";
        case S_IN_STRUCT:               return "S_IN_STRUCT";
        case S_NAME:                    return "S_NAME";
        case S_VERSION:                 return "S_VERSION";
        case S_MAX_ID:                  return "S_MAX_ID";
        case S_IMPORT_LIST:             return "S_IMPORT_LIST";
        case S_IN_IMPORTS:              return "S_IN_IMPORTS";
        case S_IMPORT_STRUCT:           return "S_IMPORT_STRUCT";
        case S_IN_IMPORT_STRUCT:        return "S_IN_IMPORT_STRUCT";
        case S_IMPORT_NAME:             return "S_IMPORT_NAME";
        case S_IMPORT_VERSION:          return "S_IMPORT_VERSION";
        case S_IMPORT_MAX_ID:           return "S_IMPORT_MAX_ID";
        case S_IMPORT_STRUCT_CLOSE:     return "S_IMPORT_STRUCT_CLOSE";
        case S_IMPORT_LIST_CLOSE:       return "S_IMPORT_LIST_CLOSE";
        case S_AFTER_IMPORT_LIST:       return "S_AFTER_IMPORT_LIST";
        case S_SYMBOL_LIST:             return "S_SYMBOL_LIST";
        case S_IN_SYMBOLS:              return "S_IN_SYMBOLS";
        case S_SYMBOL:                  return "S_SYMBOL";
        case S_SYMBOL_LIST_CLOSE:       return "S_SYMBOL_LIST_CLOSE";
        case S_STRUCT_CLOSE:            return "S_STRUCT_CLOSE";
        case S_EOF:                     return "S_EOF";
        default:                        return "";
        }
    }

    static final IonType stateType(int state)
    {
        switch (state)
        {
        case S_BOF:                  return null;
        case S_STRUCT:               return IonType.STRUCT;
        case S_IN_STRUCT:            return null;
        case S_NAME:                 return IonType.STRING;
        case S_VERSION:              return IonType.INT;
        case S_MAX_ID:               return IonType.INT;
        case S_IMPORT_LIST:          return IonType.LIST;
        case S_IN_IMPORTS:           return null;
        case S_IMPORT_STRUCT:        return IonType.STRUCT;
        case S_IN_IMPORT_STRUCT:     return null;
        case S_IMPORT_NAME:          return IonType.STRING;
        case S_IMPORT_VERSION:       return IonType.INT;
        case S_IMPORT_MAX_ID:        return IonType.INT;
        case S_IMPORT_STRUCT_CLOSE:  return null;
        case S_IMPORT_LIST_CLOSE:    return null;
        case S_AFTER_IMPORT_LIST:    return null;
        case S_SYMBOL_LIST:          return IonType.LIST;
        case S_IN_SYMBOLS:           return null;
        case S_SYMBOL:               return IonType.STRING;
        case S_SYMBOL_LIST_CLOSE:    return null;
        case S_STRUCT_CLOSE:         return null;
        case S_EOF:                  return null;
        default:
            throwUnrecognizedState(state);
            return null;
        }
    }

    static final int stateDepth(int state)
    {
        switch (state)
        {
        case S_BOF:                  return 0;
        case S_STRUCT:               return 0;
        case S_IN_STRUCT:            return 1;
        case S_NAME:                 return 1;
        case S_VERSION:              return 1;
        case S_MAX_ID:               return 1;
        case S_IMPORT_LIST:          return 1;
        case S_IN_IMPORTS:           return 2;
        case S_IMPORT_STRUCT:        return 2;
        case S_IN_IMPORT_STRUCT:     return 3;
        case S_IMPORT_NAME:          return 3;
        case S_IMPORT_VERSION:       return 3;
        case S_IMPORT_MAX_ID:        return 3;
        case S_IMPORT_STRUCT_CLOSE:  return 3;
        case S_IMPORT_LIST_CLOSE:    return 2;
        case S_AFTER_IMPORT_LIST:    return 1;
        case S_SYMBOL_LIST:          return 1;
        case S_IN_SYMBOLS:           return 2;
        case S_SYMBOL:               return 2;
        case S_SYMBOL_LIST_CLOSE:    return 2;
        case S_STRUCT_CLOSE:         return 1;
        case S_EOF:                  return 0;
        default:
            throwUnrecognizedState(state);
            return -1;
        }
    }


    /**
     * these define the bit masked flags used
     * to inform iteration over the optional
     * values that may be present
     */
    private static final int HAS_NAME           = 0x01;
    private static final int HAS_VERSION        = 0x02;
    private static final int HAS_MAX_ID         = 0x04;
    private static final int HAS_IMPORT_LIST    = 0x08;
    private static final int HAS_SYMBOL_LIST    = 0x10;


    /**
     * The symbol table we are reading.
     *
     * We MUST NOT call methods whose value may change! Otherwise there's a
     * thread-safety problem.
     */
    private final SymbolTable _symbol_table;

    private final int _maxId;

    /**
     * _state tracks the progress through the various
     * members, including the substructures in the
     * import list and symbol list.  The previous state
     * is needed when we run into an end of container.
     */
    int _current_state  = S_BOF;

    /**
     * state variables that hold the values referenced
     * by the current reader position.  These are filled
     * in by nextStateDepthFirst() and used by the value
     * getting methods.
     *
     * The iterators are opened when the user steps into
     * one of the two lists (imports and symbols).
     *
     */
    int                          _flags;                  // has name, has ... optional top level values
    String                       _string_value;
    long                         _int_value;
    private SymbolTable[]        _imported_tables;
    private Iterator _import_iterator;
    private SymbolTable          _current_import;
    Iterator             _local_symbols;

    public SymbolTableReader(SymbolTable symbol_table)
    {
        _symbol_table = symbol_table;

        synchronized (symbol_table)
        {
            _maxId = symbol_table.getMaxId();
            _local_symbols = symbol_table.iterateDeclaredSymbolNames();
        }

        if (symbol_table.isLocalTable() == false) {
            set_flag(HAS_NAME, true);
            set_flag(HAS_VERSION, true);
        }
        if (_maxId > 0) {
            // FIXME: is this ever true?            set_flag(HAS_MAX_ID, true);
        }
        _imported_tables = _symbol_table.getImportedTables();
        if (_imported_tables != null && _imported_tables.length != 0) {
            set_flag(HAS_IMPORT_LIST, true);
        }
        if (_symbol_table.getImportedMaxId() < _maxId) {
            set_flag(HAS_SYMBOL_LIST, true);
        }
    }


    /**
     * @return This implementation always returns null.
     */
    public  T asFacet(Class facetType)
    {
        return null;
    }

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


    private final void set_flag(int flag_bit, boolean flag_state)
    {
        if (flag_state) {
            _flags |= flag_bit;
        }
        else {
            _flags &= ~flag_bit;
        }
    }

    private final boolean test_flag(int flag_bit)
    {
        boolean flag_state = (_flags & flag_bit) != 0;
        return flag_state;
    }

    final boolean hasName() {
        boolean flag_state = test_flag(HAS_NAME);
        return flag_state;
    }

    final boolean hasVersion() {
        boolean flag_state = test_flag(HAS_VERSION);
        return flag_state;
    }

    final boolean hasMaxId() {
        boolean flag_state = test_flag(HAS_MAX_ID);
        return flag_state;
    }

    final boolean hasImports() {
        boolean flag_state = test_flag(HAS_IMPORT_LIST);
        return flag_state;
    }

    final boolean hasLocalSymbols() {
        boolean flag_state = test_flag(HAS_SYMBOL_LIST);
        return flag_state;
    }

    private final boolean has_next()
    {
        // this just tells us whether or not we have more
        // value coming at our current scanning depth
        switch (_current_state)
        {
        case S_BOF:
            // outer struct always follows
            return true;

        case S_STRUCT:
            // only top level value
            return false;

        case S_IN_STRUCT:
            if (stateFirstInStruct() != S_STRUCT_CLOSE) {
                return true;
            }
            return false;

        case S_NAME:
            // if we have name we have version
            return true;

        case S_VERSION:
            if (hasMaxId()) {
                return true;
            }
            if (stateFollowingMaxId() != S_STRUCT_CLOSE) {
                return true;
            }
            return false;

        case S_MAX_ID:
            // maybe something follows, but not always
            if (stateFollowingMaxId() != S_STRUCT_CLOSE) {
                return true;
            }
            return false;

        case S_IMPORT_LIST:
            // locals are the only thing that might follow imports
            if (hasLocalSymbols())  return true;
            return false;

        case S_IN_IMPORTS:
        case S_IMPORT_STRUCT:
            // we have more if there is
            boolean more_imports = _import_iterator.hasNext();
            return more_imports;

        case S_IN_IMPORT_STRUCT:
        case S_IMPORT_NAME:
            // we always have a name and version
            return true;

        case S_IMPORT_VERSION:
            // we always have a max_id on imports
            return true;

        case S_IMPORT_MAX_ID:
        case S_IMPORT_STRUCT_CLOSE:
            return false;

        case S_IMPORT_LIST_CLOSE:
            return false;

        case S_AFTER_IMPORT_LIST:
            // locals are the only thing that might follow imports
            if (hasLocalSymbols())  return true;
            return false;

        case S_SYMBOL_LIST:
            // the symbol list is the last member, so it has no "next sibling"
            // but ... just in case we put something after the local symbol list
            assert(stateFollowingLocalSymbols() == S_STRUCT_CLOSE);
            return false;

        case S_IN_SYMBOLS:
        case S_SYMBOL:
            if (_local_symbols.hasNext()) return true;
            return false;

        case S_SYMBOL_LIST_CLOSE:
        case S_STRUCT_CLOSE:
        case S_EOF:
            // these are all at the end of their respective containers
            return false;

        default:
            throwUnrecognizedState(_current_state);
            return false;
        }
    }

    private final static void throwUnrecognizedState(int state)
    {
        String message = "Internal error: "
            + "UnifiedSymbolTableReader"
            + " is in an unrecognized state: "
            + get_state_name(state);
        throw new IonException(message);
    }


    // helpers to resolve the existence of a number
    // "follow" states where the answer depends on the
    // details of the symbol table we're reading.

    private final int stateFirstInStruct()
    {
        int new_state;

        if (hasName()) {
            new_state = S_NAME;
        }
        else if (hasMaxId()) {
            new_state = S_MAX_ID;
        }
        else if (hasImports()) {
            new_state = S_IMPORT_LIST;
        }
        else if (hasLocalSymbols()) {
            new_state = S_SYMBOL_LIST;
        }
        else {
            new_state = S_STRUCT_CLOSE;
        }
        return new_state;
    }

    private final int stateFollowingMaxId()
    {
        int new_state;

        if (hasImports()) {
            new_state = S_IMPORT_LIST;
        }
        else if (hasLocalSymbols()) {
            new_state = S_SYMBOL_LIST;
        }
        else {
            new_state = S_STRUCT_CLOSE;
        }
        return new_state;
    }

    private final int nextImport()
    {
        assert(_import_iterator != null);

        int new_state;
        if (_import_iterator.hasNext()) {
            _current_import = _import_iterator.next();
            new_state = S_IMPORT_STRUCT;
        }
        else {
            // the import list is empty, so we jump to
            // the close list and null out our current
            _current_import = null;
            new_state = S_IMPORT_LIST_CLOSE;
        }
        return new_state;
    }

    private static enum Op {NEXT, STEPOUT}
    private final int stateFollowingImportList(Op op)
    {
        int new_state = -1;

        if (hasLocalSymbols()) {
            switch (op) {
            case NEXT:
                new_state = S_SYMBOL_LIST;
                break;
            case STEPOUT:
                new_state = S_AFTER_IMPORT_LIST;
                break;
            }
        }
        else {
            new_state = S_STRUCT_CLOSE;
        }
        return new_state;
    }

    private final int stateFollowingLocalSymbols()
    {
        return S_STRUCT_CLOSE;
    }

    /**
     * this computes the actual move to the next state
     *
     * It does take into account the existence or absence
     * of various properties, such as the symbol table
     * name which is only present in some symbol tables.
     *
     * This also fills in a variety of current state
     * variables that are used to return correct values
     * by the "get" methods.
     *
     */
    public IonType next()
    {
        if (has_next() == false) {
            return null;
        }
        int new_state;

        switch (_current_state)
        {
        case S_BOF:
            new_state = S_STRUCT;
            break;

        case S_STRUCT:
            new_state = S_EOF;
            break;

        case S_IN_STRUCT:
            new_state = stateFirstInStruct();
            loadStateData(new_state);
            break;

        case S_NAME:
            assert(hasVersion());
            new_state = S_VERSION;
            loadStateData(new_state);
            break;

        case S_VERSION:
            if (hasMaxId()) {
                new_state = S_MAX_ID;
                loadStateData(new_state);
            }
            else {
                new_state = stateFollowingMaxId();
            }
            break;

        case S_MAX_ID:
            new_state = stateFollowingMaxId();
            break;

        case S_IMPORT_LIST:
            new_state = this.stateFollowingImportList(Op.NEXT);
            break;

        case S_IN_IMPORTS:
        case S_IMPORT_STRUCT:
            // we only need to get the import list once, which we
            // do as we step into the import list, so it should
            // be waiting for us here.
            assert(_import_iterator != null);
            new_state = nextImport();
            break;

        case S_IN_IMPORT_STRUCT:
            // shared tables have to have a name
            new_state = S_IMPORT_NAME;
            loadStateData(new_state);
            break;

        case S_IMPORT_NAME:
            // shared tables have to have a version
            new_state = S_IMPORT_VERSION;
            loadStateData(new_state);
            break;

        case S_IMPORT_VERSION:
            // and they also always have a max id - so we set up
            // for it
            new_state = S_IMPORT_MAX_ID;
            loadStateData(new_state);
            break;

        case S_IMPORT_MAX_ID:
            new_state = S_IMPORT_STRUCT_CLOSE;
            break;

        case S_IMPORT_STRUCT_CLOSE:
            // no change here - we just bump up against this local eof
            new_state = S_IMPORT_STRUCT_CLOSE;
            break;

        case S_IMPORT_LIST_CLOSE:
            // no change here - we just bump up against this local eof
            new_state = S_IMPORT_LIST_CLOSE;
            break;

        case S_AFTER_IMPORT_LIST:
            assert(_symbol_table.getImportedMaxId() < _maxId);
            new_state = S_SYMBOL_LIST;
            break;

        case S_SYMBOL_LIST:
            assert(_symbol_table.getImportedMaxId() < _maxId);
            new_state = stateFollowingLocalSymbols();
            break;

        case S_IN_SYMBOLS:
            // we have some symbols - so we'll set up to read them,
            // which we *have* to do once and *need* to do only once.
            assert(_local_symbols != null);
            // since we only get into the symbol list if
            // there are some symbols - our next state
            // is at the first symbol
            assert(_local_symbols.hasNext() == true);
            // so we just fall through to and let the S_SYMBOL
            // state do it's thing (which it will do every time
            // we move to the next symbol)
        case S_SYMBOL:
            if (_local_symbols.hasNext())
            {
                _string_value = _local_symbols.next();
                // null means this symbol isn't defined
                new_state = S_SYMBOL;
            }
            else {
                new_state = S_SYMBOL_LIST_CLOSE;
            }
            break;

        case S_SYMBOL_LIST_CLOSE:
            // no change here - we just bump up against this local eof
            new_state = S_SYMBOL_LIST_CLOSE;
            break;

        case S_STRUCT_CLOSE:
            // no change here - we just bump up against this local eof
            new_state = S_STRUCT_CLOSE;
            break;

        case S_EOF:
            new_state = S_EOF;
            break;

        default:
            throwUnrecognizedState(_current_state);
            new_state = -1;
            break;
        }

        _current_state = new_state;
        return stateType(_current_state);
    }


    private final void loadStateData(int new_state)
    {
        switch(new_state) {
        case S_NAME:
            assert(hasName());
            String name = _symbol_table.getName();
            _string_value = name;
            assert(_string_value != null);
            break;

        case S_VERSION:
            int value = _symbol_table.getVersion();
            _int_value = value;
            assert(value != 0);
            break;

        case S_MAX_ID:
            _int_value = _maxId;
            break;

        case S_IMPORT_LIST:
        case S_SYMBOL_LIST:
            // no op to simplify the initial fields logic in next()
            break;

        case S_IMPORT_NAME:
            assert(_current_import != null);
            _string_value = _current_import.getName();
            break;

        case S_IMPORT_VERSION:
            // shared tables have to have a version
            _string_value = null;
            _int_value = _current_import.getVersion();
            break;

        case S_IMPORT_MAX_ID:
            // and they also always have a max id - so we set up
            // for it
            _int_value = _current_import.getMaxId();
            break;

        default:
            String message = "UnifiedSymbolTableReader in state "
                           + SymbolTableReader.get_state_name(new_state)
                           + " has no state to load.";
            throw new IonException(message);
        }
    }

    public void stepIn()
    {
        int new_state;

        switch (_current_state) {
        case S_STRUCT:
            new_state = S_IN_STRUCT;
            break;
        case S_IMPORT_LIST:
            _import_iterator = Arrays.asList(_imported_tables).iterator();
            new_state = S_IN_IMPORTS;
            break;
        case S_IMPORT_STRUCT:
            assert(_current_import != null);
            new_state = S_IN_IMPORT_STRUCT;
            break;
        case S_SYMBOL_LIST:
            new_state = S_IN_SYMBOLS;
            break;
        default:
            throw new IllegalStateException("current value is not a container");
        }

        _current_state = new_state;
        return;
    }

    public void stepOut()
    {
        int new_state = -1;

        switch (_current_state) {
            case S_IN_STRUCT:
            case S_NAME:
            case S_VERSION:
            case S_MAX_ID:
            case S_IMPORT_LIST:
            case S_AFTER_IMPORT_LIST:
            case S_SYMBOL_LIST:
            case S_STRUCT_CLOSE:
                // these are all top level so stepOut()
                // ends up at the end of our data
                new_state = S_EOF;
                break;

            case S_IN_IMPORTS:
            case S_IMPORT_STRUCT:
            case S_IMPORT_LIST_CLOSE:
                // if we're outside a struct, and we're in the import
                // list stepOut will be whatever follows the import list
                // close and we're done with these
                _current_import = null;
                _import_iterator = null;
                new_state = stateFollowingImportList(Op.STEPOUT);
                break;

            case S_IN_IMPORT_STRUCT:
            case S_IMPORT_NAME:
            case S_IMPORT_VERSION:
            case S_IMPORT_MAX_ID:
            case S_IMPORT_STRUCT_CLOSE:
                // if there is a next import the next state
                // will be its struct open
                // otherwise next will be the list close
                if (_import_iterator.hasNext()) {
                    new_state = S_IMPORT_STRUCT;
                }
                else {
                    new_state = S_IMPORT_LIST_CLOSE;
                }
                break;

            case S_IN_SYMBOLS:
            case S_SYMBOL:
            case S_SYMBOL_LIST_CLOSE:
                // I think this is just S_EOF, but if we ever
                // put anything after the symbol list this
                // will need to be updated.  And we're done
                // with our local symbol references.
                _string_value = null;
                _local_symbols = null;
                new_state = stateFollowingLocalSymbols();
                break;

            default:
                throw new IllegalStateException("current value is not in a container");
        }

        _current_state = new_state;
        return;
    }

    public int getDepth()
    {
        return stateDepth(_current_state);
    }

    public SymbolTable getSymbolTable()
    {
        // TODO: this should return a system symbol table
        //       but, for now, we don't really know which
        //       one to return;
        //
        // UnifiedSymbolTable.makeSystemSymbolTable(_sys, _version);
        //
        // although, with this reader in place we should be
        // able to cons one up without a system
        return null;
    }

    public IonType getType()
    {
        return stateType(_current_state);
    }


    public String[] getTypeAnnotations()
    {
        if (_current_state == S_STRUCT) {
            // Must return a new array each time to prevent user from changing it
            if (_symbol_table.isLocalTable() || _symbol_table.isSystemTable())
            {
                return new String[] { ION_SYMBOL_TABLE };
            }
            return new String[] { ION_SHARED_SYMBOL_TABLE };
        }
        return PrivateUtils.EMPTY_STRING_ARRAY;
    }

    private static final SymbolToken ION_SYMBOL_TABLE_SYM =
        newSymbolToken(ION_SYMBOL_TABLE, ION_SYMBOL_TABLE_SID);

    private static final SymbolToken ION_SHARED_SYMBOL_TABLE_SYM =
        newSymbolToken(ION_SHARED_SYMBOL_TABLE, ION_SHARED_SYMBOL_TABLE_SID);

    public SymbolToken[] getTypeAnnotationSymbols()
    {
        if (_current_state == S_STRUCT) {
            SymbolToken sym;
            if (_symbol_table.isLocalTable() || _symbol_table.isSystemTable())
            {
                sym = ION_SYMBOL_TABLE_SYM;
            }
            else
            {
                sym = ION_SHARED_SYMBOL_TABLE_SYM;
            }

            // Must return a new array each time to prevent user from changing it
            return new SymbolToken[] { sym };
        }
        return SymbolToken.EMPTY_ARRAY;
    }


    public Iterator iterateTypeAnnotations()
    {
        String[] annotations = getTypeAnnotations();
        return PrivateUtils.stringIterator(annotations);
    }

    public String getFieldName()
    {
        switch (_current_state)
        {
        case S_STRUCT:
        case S_IN_STRUCT:
        case S_IN_IMPORTS:
        case S_IMPORT_STRUCT:
        case S_IN_IMPORT_STRUCT:
        case S_IMPORT_STRUCT_CLOSE:
        case S_IMPORT_LIST_CLOSE:
        case S_AFTER_IMPORT_LIST:
        case S_IN_SYMBOLS:
        case S_SYMBOL:
        case S_SYMBOL_LIST_CLOSE:
        case S_STRUCT_CLOSE:
        case S_EOF:
            return null;

        case S_NAME:
        case S_IMPORT_NAME:
            return NAME;

        case S_VERSION:
        case S_IMPORT_VERSION:
            return VERSION;

        case S_MAX_ID:
        case S_IMPORT_MAX_ID:
            return MAX_ID;

        case S_IMPORT_LIST:
            return IMPORTS;

        case S_SYMBOL_LIST:
            return SYMBOLS;

        default:
            throw new IonException("Internal error: UnifiedSymbolTableReader is in an unrecognized state: "+_current_state);
        }
    }

    public SymbolToken getFieldNameSymbol()
    {
        switch (_current_state)
        {
        case S_STRUCT:
        case S_IN_STRUCT:
        case S_IN_IMPORTS:
        case S_IMPORT_STRUCT:
        case S_IN_IMPORT_STRUCT:
        case S_IMPORT_STRUCT_CLOSE:
        case S_IMPORT_LIST_CLOSE:
        case S_AFTER_IMPORT_LIST:
        case S_IN_SYMBOLS:
        case S_SYMBOL:
        case S_SYMBOL_LIST_CLOSE:
        case S_STRUCT_CLOSE:
        case S_EOF:
            return null;

        case S_NAME:
        case S_IMPORT_NAME:
            return new SymbolTokenImpl(NAME, NAME_SID);

        case S_VERSION:
        case S_IMPORT_VERSION:
            return new SymbolTokenImpl(VERSION, VERSION_SID);

        case S_MAX_ID:
        case S_IMPORT_MAX_ID:
            return new SymbolTokenImpl(MAX_ID, MAX_ID_SID);

        case S_IMPORT_LIST:
            return new SymbolTokenImpl(IMPORTS, IMPORTS_SID);

        case S_SYMBOL_LIST:
            return new SymbolTokenImpl(SYMBOLS, SYMBOLS_SID);

        default:
            throw new IonException("Internal error: UnifiedSymbolTableReader is in an unrecognized state: "+_current_state);
        }
    }

    public boolean isNullValue()
    {
        switch (_current_state)
        {
        case S_STRUCT:
        case S_IN_STRUCT:
        case S_NAME:
        case S_VERSION:
        case S_MAX_ID:
        case S_IMPORT_LIST:
        case S_IN_IMPORTS:
        case S_IMPORT_STRUCT:
        case S_IN_IMPORT_STRUCT:
        case S_IMPORT_NAME:
        case S_IMPORT_VERSION:
        case S_IMPORT_MAX_ID:
        case S_IN_SYMBOLS:
        case S_SYMBOL:
            // these values are either present and non-null
            // or entirely absent (in which case they will
            // have been skipped and we won't be in a state
            // to return them).
            return false;

        case S_IMPORT_STRUCT_CLOSE:
        case S_IMPORT_LIST_CLOSE:
        case S_AFTER_IMPORT_LIST:
        case S_SYMBOL_LIST:
        case S_SYMBOL_LIST_CLOSE:
        case S_STRUCT_CLOSE:
        case S_EOF:
            // here we're not really on a value, so we're not
            // on a value that is a null - so false again.
            return false;

        default:
            throw new IonException("Internal error: UnifiedSymbolTableReader is in an unrecognized state: "+_current_state);
        }
    }

    public boolean isInStruct()
    {
        switch (_current_state)
        {
        case S_STRUCT:
        case S_IN_IMPORTS:
        case S_IMPORT_STRUCT:
        case S_IN_SYMBOLS:
        case S_SYMBOL:
            // these values are either not contained, or
            // contained in a list.  So we aren't in a
            // struct if they're pending.
            return false;

        case S_IN_STRUCT:
        case S_NAME:
        case S_VERSION:
        case S_MAX_ID:
        case S_IMPORT_LIST:
        case S_IN_IMPORT_STRUCT:
        case S_IMPORT_NAME:
        case S_IMPORT_VERSION:
        case S_IMPORT_MAX_ID:
        case S_AFTER_IMPORT_LIST:
        case S_SYMBOL_LIST:
            // the values above are all members
            // of a struct, so we must be in a
            // struct to have them pending
            return true;

        case S_IMPORT_STRUCT_CLOSE:
        case S_STRUCT_CLOSE:
            // if we're closing a struct we're in a struct
            return true;

        case S_IMPORT_LIST_CLOSE:
        case S_SYMBOL_LIST_CLOSE:
        case S_EOF:
            // if we're closing a list we in a list, not a struct
            // and EOF is not in a struct
            return false;

        default:
            throw new IonException("Internal error: UnifiedSymbolTableReader is in an unrecognized state: "+_current_state);
        }
    }

    public boolean booleanValue()
    {
        throw new IllegalStateException("only valid if the value is a boolean");
    }

    public int intValue()
    {
        return (int)_int_value;
    }

    public long longValue()
    {
        return _int_value;
    }

    public BigInteger bigIntegerValue()
    {
        String value = Long .toString(_int_value);
        BigInteger bi = new BigInteger(value);     // this is SOOOOO broken 
        return bi;
    }

    public double doubleValue()
    {
        throw new IllegalStateException("only valid if the value is a double");
    }

    public BigDecimal bigDecimalValue()
    {
        throw new IllegalStateException("only valid if the value is a decimal");    }

    public Decimal decimalValue()
    {
        throw new IllegalStateException("only valid if the value is a decimal");
    }

    public Date dateValue()
    {
        throw new IllegalStateException("only valid if the value is a timestamp");
    }

    public Timestamp timestampValue()
    {
        throw new IllegalStateException("only valid if the value is a timestamp");
    }

    public String stringValue()
    {
        return _string_value;
    }

    public SymbolToken symbolValue()
    {
        // TODO handle null
        throw new UnsupportedOperationException();
    }

    public int getBytes(byte[] buffer, int offset, int len)
    {
        throw new IllegalStateException("getBytes() is only valid if the reader is on a lob value, not a "+stateType(_current_state)+" value");
    }

    public int byteSize()
    {
        throw new IllegalStateException("byteSize() is only valid if the reader is on a lob value, not a "+stateType(_current_state)+" value");
    }

    public byte[] newBytes()
    {
        throw new IllegalStateException("newBytes() is only valid if the reader is on a lob value, not a "+stateType(_current_state)+" value");
    }

    public void close() throws IOException
    {
        _current_state = S_EOF;
    }

    public IntegerSize getIntegerSize()
    {
        if (stateType(_current_state) != IonType.INT)
        {
            return null;
        }
        return IntegerSize.INT; // all of SymbolTable's integers are type int
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy