content: /*
   * Copyright (c) 2001-2004 Caucho Technology, Inc.  All rights reserved.
   *
   * The Apache Software License, Version 1.1
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   *
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer.
   *
   * 2. Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in
   *    the documentation and/or other materials provided with the
   *    distribution.
   *
   * 3. The end-user documentation included with the redistribution, if
   *    any, must include the following acknowlegement:
   *       "This product includes software developed by the
   *        Caucho Technology (http://www.caucho.com/)."
   *    Alternately, this acknowlegement may appear in the software itself,
   *    if and wherever such third-party acknowlegements normally appear.
   *
   * 4. The names "Hessian", "Resin", and "Caucho" must not be used to
   *    endorse or promote products derived from this software without prior
   *    written permission. For written permission, please contact
   *    info@caucho.com.
   *
   * 5. Products derived from this software may not be called "Resin"
   *    nor may "Resin" appear in their names without prior written
   *    permission of Caucho Technology.
   *
   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED.  IN NO EVENT SHALL CAUCHO TECHNOLOGY OR ITS CONTRIBUTORS
   * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
   * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
   * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
   * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
   * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
   * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
   * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   *
   * @author Scott Ferguson
   */
  
  package com.caucho.hessian.io;
  
  import java.io.IOException;
  import java.io.PrintWriter;
  import java.util.ArrayList;
  import java.util.logging.Logger;
  
  /**
   * Debugging input stream for Hessian requests.
   */
  public class HessianDebugState implements Hessian2Constants
  {
    private static final Logger log
      = Logger.getLogger(HessianDebugState.class.getName());
    
    private PrintWriter _dbg;
  
    private State _state;
    private ArrayList<State> _stateStack = new ArrayList<State>();
  
    private ArrayList<ObjectDef> _objectDefList
      = new ArrayList<ObjectDef>();
  
    private ArrayList<String> _typeDefList
      = new ArrayList<String>();
  
    private int _refId;
    private boolean _isNewline = true;
    private boolean _isObject = false;
    private int _column;
  
    private int _depth = 0;
    
    /**
     * Creates an uninitialized Hessian input stream.
     */
    public HessianDebugState(PrintWriter dbg)
    {
      _dbg = dbg;
  
      _state = new InitialState();
    }
  
    public void startTop2()
    {
      _state = new Top2State();
    }
  
    public void startData1()
    {
      _state = new InitialState1();
    }
  
    public void startStreaming()
    {
      _state = new StreamingState(new InitialState(), false);
    }
  
    /**
     * Reads a character.
     */
    public void next(int ch)
      throws IOException
    {
      _state = _state.next(ch);
    }
  
    void pushStack(State state)
    {
      _stateStack.add(state);
    }
  
    State popStack()
    {
      return _stateStack.remove(_stateStack.size() - 1);
    }
  
    public void setDepth(int depth)
    {
      _depth = depth;
    }
  
    public int getDepth()
    {
      return _depth;
    }
  
    void println()
    {
      if (! _isNewline) {
        _dbg.println();
        _dbg.flush();
      }
  
      _isNewline = true;
      _column = 0;
    }
  
    static boolean isString(int ch)
    {
      switch (ch) {
      case 0x00: case 0x01: case 0x02: case 0x03:
      case 0x04: case 0x05: case 0x06: case 0x07:
      case 0x08: case 0x09: case 0x0a: case 0x0b:
      case 0x0c: case 0x0d: case 0x0e: case 0x0f:
  
      case 0x10: case 0x11: case 0x12: case 0x13:
      case 0x14: case 0x15: case 0x16: case 0x17:
      case 0x18: case 0x19: case 0x1a: case 0x1b:
      case 0x1c: case 0x1d: case 0x1e: case 0x1f:
  
      case 0x30: case 0x31: case 0x32: case 0x33:
  
      case 'R':
      case 'S':
        return true;
  
      default:
        return false;
      }
    }
  
    static boolean isInteger(int ch)
    {
      switch (ch) {
      case 0x80: case 0x81: case 0x82: case 0x83: 
      case 0x84: case 0x85: case 0x86: case 0x87: 
      case 0x88: case 0x89: case 0x8a: case 0x8b: 
      case 0x8c: case 0x8d: case 0x8e: case 0x8f: 
  
      case 0x90: case 0x91: case 0x92: case 0x93: 
      case 0x94: case 0x95: case 0x96: case 0x97: 
      case 0x98: case 0x99: case 0x9a: case 0x9b: 
      case 0x9c: case 0x9d: case 0x9e: case 0x9f: 
  
      case 0xa0: case 0xa1: case 0xa2: case 0xa3: 
      case 0xa4: case 0xa5: case 0xa6: case 0xa7: 
      case 0xa8: case 0xa9: case 0xaa: case 0xab: 
      case 0xac: case 0xad: case 0xae: case 0xaf: 
  
      case 0xb0: case 0xb1: case 0xb2: case 0xb3: 
      case 0xb4: case 0xb5: case 0xb6: case 0xb7: 
      case 0xb8: case 0xb9: case 0xba: case 0xbb: 
      case 0xbc: case 0xbd: case 0xbe: case 0xbf:
  
      case 0xc0: case 0xc1: case 0xc2: case 0xc3: 
      case 0xc4: case 0xc5: case 0xc6: case 0xc7: 
      case 0xc8: case 0xc9: case 0xca: case 0xcb: 
      case 0xcc: case 0xcd: case 0xce: case 0xcf:
  
      case 0xd0: case 0xd1: case 0xd2: case 0xd3: 
      case 0xd4: case 0xd5: case 0xd6: case 0xd7: 
  
      case 'I':
        return true;
  
      default:
        return false;
      }
    }
  
    abstract class State {
      State _next;
  
      State()
      {
      }
  
      State(State next)
      {
        _next = next;
      }
      
      abstract State next(int ch);
  
      boolean isShift(Object value)
      {
        return false;
      }
  
      State shift(Object value)
      {
        return this;
      }
  
      int depth()
      {
        if (_next != null)
          return _next.depth();
        else
          return HessianDebugState.this.getDepth();
      }
  
      void printIndent(int depth)
      {
        if (_isNewline) {
          for (int i = _column; i < depth() + depth; i++) {
            _dbg.print(" ");
            _column++;
          }
        }
      }
  
      void print(String string)
      {
        print(0, string);
      }
  
      void print(int depth, String string)
      {
        printIndent(depth);
        
        _dbg.print(string);
        _isNewline = false;
        _isObject = false;
  
        int p = string.lastIndexOf('\n');
        if (p > 0)
          _column = string.length() - p - 1;
        else
          _column += string.length();
      }
  
      void println(String string)
      {
        println(0, string);
      }
  
      void println(int depth, String string)
      {
        printIndent(depth);
  
        _dbg.println(string);
        _dbg.flush();
        _isNewline = true;
        _isObject = false;
        _column = 0;
      }
  
      void println()
      {
        if (! _isNewline) {
          _dbg.println();
          _dbg.flush();
        }
  
        _isNewline = true;
        _isObject = false;
        _column = 0;
      }
  
      void printObject(String string)
      {
        if (_isObject)
          println();
        
        printIndent(0);
  
        _dbg.print(string);
        _dbg.flush();
  
        _column += string.length();
  
        _isNewline = false;
        _isObject = true;
      }
      
      protected State nextObject(int ch)
      {
        switch (ch) {
        case -1:
          println();
          return this;
  
        case 'N':
          if (isShift(null))
            return shift(null);
          else {
            printObject("null");
            return this;
          }
  
        case 'T':
          if (isShift(Boolean.TRUE))
            return shift(Boolean.TRUE);
          else {
            printObject("true");
            return this;
          }
  
        case 'F':
          if (isShift(Boolean.FALSE))
            return shift(Boolean.FALSE);
          else {
            printObject("false");
            return this;
          }
  
        case 0x80: case 0x81: case 0x82: case 0x83: 
        case 0x84: case 0x85: case 0x86: case 0x87: 
        case 0x88: case 0x89: case 0x8a: case 0x8b: 
        case 0x8c: case 0x8d: case 0x8e: case 0x8f: 
  
        case 0x90: case 0x91: case 0x92: case 0x93: 
        case 0x94: case 0x95: case 0x96: case 0x97: 
        case 0x98: case 0x99: case 0x9a: case 0x9b: 
        case 0x9c: case 0x9d: case 0x9e: case 0x9f: 
  
        case 0xa0: case 0xa1: case 0xa2: case 0xa3: 
        case 0xa4: case 0xa5: case 0xa6: case 0xa7: 
        case 0xa8: case 0xa9: case 0xaa: case 0xab: 
        case 0xac: case 0xad: case 0xae: case 0xaf: 
  
        case 0xb0: case 0xb1: case 0xb2: case 0xb3: 
        case 0xb4: case 0xb5: case 0xb6: case 0xb7: 
        case 0xb8: case 0xb9: case 0xba: case 0xbb: 
        case 0xbc: case 0xbd: case 0xbe: case 0xbf:
          {
            Integer value = new Integer(ch - 0x90);
  
            if (isShift(value))
              return shift(value);
            else {
              printObject(value.toString());
              return this;
            }
          }
  
        case 0xc0: case 0xc1: case 0xc2: case 0xc3: 
        case 0xc4: case 0xc5: case 0xc6: case 0xc7: 
        case 0xc8: case 0xc9: case 0xca: case 0xcb: 
        case 0xcc: case 0xcd: case 0xce: case 0xcf:
          return new IntegerState(this, "int", ch - 0xc8, 3);
  
        case 0xd0: case 0xd1: case 0xd2: case 0xd3: 
        case 0xd4: case 0xd5: case 0xd6: case 0xd7: 
          return new IntegerState(this, "int", ch - 0xd4, 2);
  
        case 'I':
          return new IntegerState(this, "int");
  
        case 0xd8: case 0xd9: case 0xda: case 0xdb: 
        case 0xdc: case 0xdd: case 0xde: case 0xdf: 
        case 0xe0: case 0xe1: case 0xe2: case 0xe3: 
        case 0xe4: case 0xe5: case 0xe6: case 0xe7: 
        case 0xe8: case 0xe9: case 0xea: case 0xeb: 
        case 0xec: case 0xed: case 0xee: case 0xef:
          {
            Long value = new Long(ch - 0xe0);
  
            if (isShift(value))
              return shift(value);
            else {
              printObject(value.toString() + "L");
              return this;
            }
          }
  
        case 0xf0: case 0xf1: case 0xf2: case 0xf3: 
        case 0xf4: case 0xf5: case 0xf6: case 0xf7: 
        case 0xf8: case 0xf9: case 0xfa: case 0xfb: 
        case 0xfc: case 0xfd: case 0xfe: case 0xff:
          return new LongState(this, "long", ch - 0xf8, 7);
  
        case 0x38: case 0x39: case 0x3a: case 0x3b: 
        case 0x3c: case 0x3d: case 0x3e: case 0x3f:
          return new LongState(this, "long", ch - 0x3c, 6);
  
        case BC_LONG_INT:
          return new LongState(this, "long", 0, 4);
  
        case 'L':
          return new LongState(this, "long");
  
        case 0x5b: case 0x5c:
          {
            Double value = new Double(ch - 0x5b);
  
            if (isShift(value))
              return shift(value);
            else {
              printObject(value.toString());
              return this;
            }
          }
  
        case 0x5d:
          return new DoubleIntegerState(this, 3);
  
        case 0x5e:
          return new DoubleIntegerState(this, 2);
  
        case 0x5f:
          return new MillsState(this);
  
        case 'D':
          return new DoubleState(this);
  
        case 'Q':
          return new RefState(this);
  
        case BC_DATE:
          return new DateState(this);
  
        case BC_DATE_MINUTE:
          return new DateState(this, true);
  
        case 0x00:
          {
            String value = "\"\"";
  
            if (isShift(value))
              return shift(value);
            else {
              printObject(value.toString());
              return this;
            }
          }
  
        case 0x01: case 0x02: case 0x03:
        case 0x04: case 0x05: case 0x06: case 0x07:
        case 0x08: case 0x09: case 0x0a: case 0x0b:
        case 0x0c: case 0x0d: case 0x0e: case 0x0f:
  
        case 0x10: case 0x11: case 0x12: case 0x13:
        case 0x14: case 0x15: case 0x16: case 0x17:
        case 0x18: case 0x19: case 0x1a: case 0x1b:
        case 0x1c: case 0x1d: case 0x1e: case 0x1f:
          return new StringState(this, 'S', ch);
  
        case 0x30: case 0x31: case 0x32: case 0x33:
          return new StringState(this, 'S', ch - 0x30, true);
  
        case 'R':
          return new StringState(this, 'S', false);
  
        case 'S':
          return new StringState(this, 'S', true);
  
        case 0x20:
          {
            String value = "binary(0)";
  
            if (isShift(value))
              return shift(value);
            else {
              printObject(value.toString());
              return this;
            }
          }
  
        case 0x21: case 0x22: case 0x23:
        case 0x24: case 0x25: case 0x26: case 0x27:
        case 0x28: case 0x29: case 0x2a: case 0x2b:
        case 0x2c: case 0x2d: case 0x2e: case 0x2f:
          return new BinaryState(this, 'B', ch - 0x20);
  
        case 0x34: case 0x35: case 0x36: case 0x37:
          return new BinaryState(this, 'B', ch - 0x34, true);
  
        case 'A':
          return new BinaryState(this, 'B', false);
  
        case 'B':
          return new BinaryState(this, 'B', true);
  
        case 'M':
          return new MapState(this, _refId++);
  
        case 'H':
          return new MapState(this, _refId++, false);
  
        case BC_LIST_VARIABLE:
          return new ListState(this, _refId++, true);
  
        case BC_LIST_VARIABLE_UNTYPED:
          return new ListState(this, _refId++, false);
  
        case BC_LIST_FIXED:
          return new CompactListState(this, _refId++, true);
  
        case BC_LIST_FIXED_UNTYPED:
          return new CompactListState(this, _refId++, false);
  
        case 0x70: case 0x71: case 0x72: case 0x73:
        case 0x74: case 0x75: case 0x76: case 0x77:
          return new CompactListState(this, _refId++, true, ch - 0x70);
  
        case 0x78: case 0x79: case 0x7a: case 0x7b:
        case 0x7c: case 0x7d: case 0x7e: case 0x7f:
          return new CompactListState(this, _refId++, false, ch - 0x78);
  
        case 'C':
          return new ObjectDefState(this);
  
        case 0x60: case 0x61: case 0x62: case 0x63:
        case 0x64: case 0x65: case 0x66: case 0x67:
        case 0x68: case 0x69: case 0x6a: case 0x6b:
        case 0x6c: case 0x6d: case 0x6e: case 0x6f:
          return new ObjectState(this, _refId++, ch - 0x60);
  
        case 'O':
          return new ObjectState(this, _refId++);
  
        default:
          return this;
        }
      }
    }
  
    abstract class State1 extends State {
      State1()
      {
      }
  
      State1(State next)
      {
        super(next);
      }
      
      protected State nextObject(int ch)
      {
        switch (ch) {
        case -1:
          println();
          return this;
  
        case 'N':
          if (isShift(null))
            return shift(null);
          else {
            printObject("null");
            return this;
          }
  
        case 'T':
          if (isShift(Boolean.TRUE))
            return shift(Boolean.TRUE);
          else {
            printObject("true");
            return this;
          }
  
        case 'F':
          if (isShift(Boolean.FALSE))
            return shift(Boolean.FALSE);
          else {
            printObject("false");
            return this;
          }
  
        case 'I':
          return new IntegerState(this, "int");
  
        case 'L':
          return new LongState(this, "long");
  
        case 'D':
          return new DoubleState(this);
  
        case 'Q':
          return new RefState(this);
  
        case 'd':
          return new DateState(this);
  
        case 's':
          return new StringState(this, 'S', false);
  
        case 'S':
          return new StringState(this, 'S', true);
  
        case 'b':
        case 'A':
          return new BinaryState(this, 'B', false);
  
        case 'B':
          return new BinaryState(this, 'B', true);
  
        case 'M':
          return new MapState1(this, _refId++);
  
        case 'V':
          return new ListState1(this, _refId++);
  
        case 'R':
          return new IntegerState(new RefState1(this), "ref");
  
        default:
          printObject("x" + String.format("%02x", ch));
          return this;
        }
      }
    }
    
    class InitialState extends State {
      State next(int ch)
      {
        return nextObject(ch);
      }
    }
    
    class InitialState1 extends State1 {
      State next(int ch)
      {
        return nextObject(ch);
      }
    }
    
    class Top1State extends State1 {
      State next(int ch)
      {
        println();
        
        if (ch == 'r') {
          return new ReplyState1(this);
        }
        else if (ch == 'c') {
          return new CallState1(this);
        }
        else
          return nextObject(ch);
      }
    }
    
    class Top2State extends State {
      State next(int ch)
      {
        println();
        
        if (ch == 'R') {
          return new Reply2State(this);
        }
        else if (ch == 'F') {
          return new Fault2State(this);
        }
        else if (ch == 'C') {
          return new Call2State(this);
        }
        else if (ch == 'H') {
          return new Hessian2State(this);
        }
        else if (ch == 'r') {
          return new ReplyState1(this);
        }
        else if (ch == 'c') {
          return new CallState1(this);
        }
        else
          return nextObject(ch);
      }
    }
    
    class IntegerState extends State {
      String _typeCode;
      
      int _length;
      int _value;
  
      IntegerState(State next, String typeCode)
      {
        super(next);
  
        _typeCode = typeCode;
      }
  
      IntegerState(State next, String typeCode, int value, int length)
      {
        super(next);
  
        _typeCode = typeCode;
  
        _value = value;
        _length = length;
      }
  
      State next(int ch)
      {
        _value = 256 * _value + (ch & 0xff);
  
        if (++_length == 4) {
          Integer value = new Integer(_value);
  
          if (_next.isShift(value))
            return _next.shift(value);
          else {
            printObject(value.toString());
  
            return _next;
          }
        }
        else
          return this;
      }
    }
    
    class LongState extends State {
      String _typeCode;
      
      int _length;
      long _value;
  
      LongState(State next, String typeCode)
      {
        super(next);
  
        _typeCode = typeCode;
      }
  
      LongState(State next, String typeCode, long value, int length)
      {
        super(next);
  
        _typeCode = typeCode;
  
        _value = value;
        _length = length;
      }
  
      State next(int ch)
      {
        _value = 256 * _value + (ch & 0xff);
  
        if (++_length == 8) {
          Long value = new Long(_value);
  
          if (_next.isShift(value))
            return _next.shift(value);
          else {
            printObject(value.toString() + "L");
  
            return _next;
          }
        }
        else
          return this;
      }
    }
    
    class DoubleIntegerState extends State {
      int _length;
      int _value;
      boolean _isFirst = true;
  
      DoubleIntegerState(State next, int length)
      {
        super(next);
  
        _length = length;
      }
  
      State next(int ch)
      {
        if (_isFirst)
          _value = (byte) ch;
        else
          _value = 256 * _value + (ch & 0xff);
  
        _isFirst = false;
  
        if (++_length == 4) {
          Double value = new Double(_value);
  
          if (_next.isShift(value))
            return _next.shift(value);
          else {
            printObject(value.toString());
  
            return _next;
          }
        }
        else
          return this;
      }
    }
    
    class RefState extends State {
      String _typeCode;
      
      int _length;
      int _value;
  
      RefState(State next)
      {
        super(next);
      }
  
      RefState(State next, String typeCode)
      {
        super(next);
  
        _typeCode = typeCode;
      }
  
      RefState(State next, String typeCode, int value, int length)
      {
        super(next);
  
        _typeCode = typeCode;
  
        _value = value;
        _length = length;
      }
  
      @Override
      boolean isShift(Object o)
      {
        return true;
      }
  
      @Override
      State shift(Object o)
      {
        println("ref #" + o);
  
        return _next;
      }
  
      @Override
      State next(int ch)
      {
        return nextObject(ch);
      }
    }
    
    class RefState1 extends State {
      String _typeCode;
      
      RefState1(State next)
      {
        super(next);
      }
  
      @Override
      boolean isShift(Object o)
      {
        return true;
      }
  
      @Override
      State shift(Object o)
      {
        println("ref #" + o);
  
        return _next;
      }
  
      @Override
      State next(int ch)
      {
        return nextObject(ch);
      }
    }
    
    class DateState extends State {
      int _length;
      long _value;
      boolean _isMinute;
  
      DateState(State next)
      {
        super(next);
      }
  
      DateState(State next, boolean isMinute)
      {
        super(next);
  
        _length = 4;
        _isMinute = isMinute;
      }
        
      
      State next(int ch)
      {
        _value = 256 * _value + (ch & 0xff);
  
        if (++_length == 8) {
          java.util.Date value;
  
          if (_isMinute)
            value = new java.util.Date(_value * 60000L);
          else
            value = new java.util.Date(_value);
  
          if (_next.isShift(value))
            return _next.shift(value);
          else {
            printObject(value.toString());
  
            return _next;
          }
        }
        else
          return this;
      }
    }
    
    class DoubleState extends State {
      int _length;
      long _value;
  
      DoubleState(State next)
      {
        super(next);
      }
      
      State next(int ch)
      {
        _value = 256 * _value + (ch & 0xff);
  
        if (++_length == 8) {
          Double value = Double.longBitsToDouble(_value);
  
          if (_next.isShift(value))
            return _next.shift(value);
          else {
            printObject(value.toString());
  
            return _next;
          }
        }
        else
          return this;
      }
    }
    
    class MillsState extends State {
      int _length;
      int _value;
  
      MillsState(State next)
      {
        super(next);
      }
      
      State next(int ch)
      {
        _value = 256 * _value + (ch & 0xff);
  
        if (++_length == 4) {
          Double value = 0.001 * _value;
  
          if (_next.isShift(value))
            return _next.shift(value);
          else {
            printObject(value.toString());
  
            return _next;
          }
        }
        else
          return this;
      }
    }
    
    class StringState extends State {
      private static final int TOP = 0;
      private static final int UTF_2_1 = 1;
      private static final int UTF_3_1 = 2;
      private static final int UTF_3_2 = 3;
  
      char _typeCode;
      
      StringBuilder _value = new StringBuilder();
      int _lengthIndex;
      int _length;
      boolean _isLastChunk;
      
      int _utfState;
      char _ch;
  
      StringState(State next, char typeCode, boolean isLastChunk)
      {
        super(next);
        
        _typeCode = typeCode;
        _isLastChunk = isLastChunk;
      }
  
      StringState(State next, char typeCode, int length)
      {
        super(next);
        
        _typeCode = typeCode;
        _isLastChunk = true;
        _length = length;
        _lengthIndex = 2;
      }
  
      StringState(State next, char typeCode, int length, boolean isLastChunk)
      {
        super(next);
        
        _typeCode = typeCode;
        _isLastChunk = isLastChunk;
        _length = length;
        _lengthIndex = 1;
      }
      
      State next(int ch)
      {
        if (_lengthIndex < 2) {
          _length = 256 * _length + (ch & 0xff);
  
          if (++_lengthIndex == 2 && _length == 0 && _isLastChunk) {
            if (_next.isShift(_value.toString()))
              return _next.shift(_value.toString());
            else {
              printObject("\"" + _value + "\"");
              return _next;
            }
          }
          else
            return this;
        }
        else if (_length == 0) {
          if (ch == 's' || ch == 'x') {
            _isLastChunk = false;
            _lengthIndex = 0;
            return this;
          }
          else if (ch == 'S' || ch == 'X') {
            _isLastChunk = true;
            _lengthIndex = 0;
            return this;
          }
          else if (ch == 0x00) {
            if (_next.isShift(_value.toString()))
              return _next.shift(_value.toString());
            else {
              printObject("\"" + _value + "\"");
              return _next;
            }
          }
          else if (0x00 <= ch && ch < 0x20) {
            _isLastChunk = true;
            _lengthIndex = 2;
            _length = ch & 0xff;
            return this;
          }
          else if (0x30 <= ch && ch < 0x34) {
            _isLastChunk = true;
            _lengthIndex = 1;
            _length = (ch - 0x30);
            return this;
          }
          else {
            println(this + " " + String.valueOf((char) ch) + ": unexpected character");
            return _next;
          }
        }
  
        switch (_utfState) {
        case TOP:
          if (ch < 0x80) {
            _length--;
  
            _value.append((char) ch);
          }
          else if (ch < 0xe0) {
            _ch = (char) ((ch & 0x1f) << 6);
            _utfState = UTF_2_1;
          }
          else {
            _ch = (char) ((ch & 0xf) << 12);
            _utfState = UTF_3_1;
          }
          break;
  
        case UTF_2_1:
        case UTF_3_2:
          _ch += ch & 0x3f;
          _value.append(_ch);
          _length--;
          _utfState = TOP;
          break;
  
        case UTF_3_1:
          _ch += (char) ((ch & 0x3f) << 6);
          _utfState = UTF_3_2;
          break;
        }
  
        if (_length == 0 && _isLastChunk) {
          if (_next.isShift(_value.toString()))
            return _next.shift(_value.toString());
          else {
            printObject("\"" + _value + "\"");
  
            return _next;
          }
        }
        else
          return this;
      }
    }
    
    class BinaryState extends State {
      char _typeCode;
      
      int _totalLength;
      
      int _lengthIndex;
      int _length;
      boolean _isLastChunk;
      
      BinaryState(State next, char typeCode, boolean isLastChunk)
      {
        super(next);
  
        _typeCode = typeCode;
        _isLastChunk = isLastChunk;
      }
  
      BinaryState(State next, char typeCode, int length)
      {
        super(next);
  
        _typeCode = typeCode;
        _isLastChunk = true;
        _length = length;
        _lengthIndex = 2;
      }
  
      BinaryState(State next, char typeCode, int length, boolean isLastChunk)
      {
        super(next);
        
        _typeCode = typeCode;
        _isLastChunk = isLastChunk;
        _length = length;
        _lengthIndex = 1;
      }
      
      @Override
      State next(int ch)
      {
        if (_lengthIndex < 2) {
          _length = 256 * _length + (ch & 0xff);
  
          if (++_lengthIndex == 2 && _length == 0 && _isLastChunk) {
            String value = "binary(" + _totalLength + ")";
  
            if (_next.isShift(value))
              return _next.shift(value);
            else {
              printObject(value);
              return _next;
            }
          }
          else
            return this;
        }
        else if (_length == 0) {
          if (ch == 'b' || ch == 'A') {
            _isLastChunk = false;
            _lengthIndex = 0;
            return this;
          }
          else if (ch == 'B') {
            _isLastChunk = true;
            _lengthIndex = 0;
            return this;
          }
          else if (ch == 0x20) {
            String value = "binary(" + _totalLength + ")";
  
            if (_next.isShift(value))
              return _next.shift(value);
            else {
              printObject(value);
              return _next;
            }
          }
          else if (0x20 <= ch && ch < 0x30) {
            _isLastChunk = true;
            _lengthIndex = 2;
            _length = (ch & 0xff) - 0x20;
            return this;
          }
          else {
            println(this + " 0x" + Integer.toHexString(ch) + " " + String.valueOf((char) ch) + ": unexpected character");
            return _next;
          }
        }
        
        _length--;
        _totalLength++;
  
        if (_length == 0 && _isLastChunk) {
          String value = "binary(" + _totalLength + ")";
  
          if (_next.isShift(value))
            return _next.shift(value);
          else {
            printObject(value);
  
            return _next;
          }
        }
        else
          return this;
      }
    }
    
    class MapState extends State {
      private static final int TYPE = 0;
      private static final int KEY = 1;
      private static final int VALUE = 2;
  
      private int _refId;
  
      private int _state;
      private int _valueDepth;
      private boolean _hasData;
  
      MapState(State next, int refId)
      {
        super(next);
        
        _refId = refId;
        _state = TYPE;
      }
  
      MapState(State next, int refId, boolean isType)
      {
        super(next);
        
        _refId = refId;
  
        if (isType)
          _state = TYPE;
        else {
          printObject("map (#" + _refId + ")");
          _state = VALUE;
        }
      }
  
      @Override
      boolean isShift(Object value)
      {
        return _state == TYPE;
      }
  
      @Override
      State shift(Object type)
      {
        if (_state == TYPE) {
          if (type instanceof String) {
            _typeDefList.add((String) type);
          }
          else if (type instanceof Integer) {
            int iValue = (Integer) type;
  
            if (iValue >= 0 && iValue < _typeDefList.size())
              type = _typeDefList.get(iValue);
          }
  
          printObject("map " + type + " (#" + _refId + ")");
  
          _state = VALUE;
        
          return this;
        }
        else {
          printObject(this + " unknown shift state= " + _state + " type=" + type);
          
          return this;
        }
      }
  
      @Override
      int depth()
      {
        if (_state == TYPE)
          return _next.depth();
        else if (_state == KEY)
          return _next.depth() + 2;
        else
          return _valueDepth;
      }
      
      State next(int ch)
      {
        switch (_state) {
        case TYPE:
          return nextObject(ch);
  
        case VALUE:
          if (ch == 'Z') {
            if (_hasData)
              println();
  
            return _next;
          }
          else {
            if (_hasData)
              println();
  
            _hasData = true;
            _state = KEY;
  
            return nextObject(ch);
          }
  
        case KEY:
          print(" => ");
          _isObject = false;
          _valueDepth = _column;
  
          _state = VALUE;
  
          return nextObject(ch);
  
        default:
          throw new IllegalStateException();
        }
      }
    }
    
    class MapState1 extends State1 {
      private static final int TYPE = 0;
      private static final int KEY = 1;
      private static final int VALUE = 2;
  
      private int _refId;
  
      private int _state;
      private int _valueDepth;
      private boolean _hasData;
  
      MapState1(State next, int refId)
      {
        super(next);
        
        _refId = refId;
        _state = TYPE;
      }
  
      MapState1(State next, int refId, boolean isType)
      {
        super(next);
        
        _refId = refId;
  
        if (isType)
          _state = TYPE;
        else {
          printObject("map (#" + _refId + ")");
          _state = VALUE;
        }
      }
  
      @Override
      boolean isShift(Object value)
      {
        return _state == TYPE;
      }
  
      @Override
      State shift(Object type)
      {
        if (_state == TYPE) {
          if (type instanceof String) {
            _typeDefList.add((String) type);
          }
          else if (type instanceof Integer) {
            int iValue = (Integer) type;
  
            if (iValue >= 0 && iValue < _typeDefList.size())
              type = _typeDefList.get(iValue);
          }
  
          printObject("map " + type + " (#" + _refId + ")");
  
          _state = VALUE;
        
          return this;
        }
        else
          throw new IllegalStateException();
      }
  
      @Override
      int depth()
      {
        if (_state == TYPE)
          return _next.depth();
        else if (_state == KEY)
          return _next.depth() + 2;
        else
          return _valueDepth;
      }
      
      State next(int ch)
      {
        switch (_state) {
        case TYPE:
          if (ch == 't') {
            return new StringState(this, 't', true);
          }
          else if (ch == 'z') {
            println("map (#" + _refId + ")");
            return _next;
          }
          else {
            println("map (#" + _refId + ")");
            _hasData = true;
            _state = KEY;
            return nextObject(ch);
          }
  
        case VALUE:
          if (ch == 'z') {
            if (_hasData)
              println();
  
            return _next;
          }
          else {
            if (_hasData)
              println();
  
            _hasData = true;
            _state = KEY;
  
            return nextObject(ch);
          }
  
        case KEY:
          print(" => ");
          _isObject = false;
          _valueDepth = _column;
  
          _state = VALUE;
  
          return nextObject(ch);
  
        default:
          throw new IllegalStateException();
        }
      }
    }
    
    class ObjectDefState extends State {
      private static final int TYPE = 1;
      private static final int COUNT = 2;
      private static final int FIELD = 3;
      private static final int COMPLETE = 4;
  
      private int _state;
      private int _count;
  
      private String _type;
      private ArrayList<String> _fields = new ArrayList<String>();
  
      ObjectDefState(State next)
      {
        super(next);
        
        _state = TYPE;
      }
  
      @Override
      boolean isShift(Object value)
      {
        return true;
      }
  
      @Override
      State shift(Object object)
      {
        if (_state == TYPE) {
          _type = (String) object;
  
          print("/* defun " + _type + " [");
  
          _objectDefList.add(new ObjectDef(_type, _fields));
  
          _state = COUNT;
        }
        else if (_state == COUNT) {
          _count = (Integer) object;
  
          _state = FIELD;
        }
        else if (_state == FIELD) {
          String field = (String) object;
  
          _count--;
  
          _fields.add(field);
  
          if (_fields.size() == 1)
            print(field);
          else
            print(", " + field);
        }
        else {
          throw new UnsupportedOperationException();
        }
  
        return this;
      }
  
      @Override
      int depth()
      {
        if (_state <= TYPE)
          return _next.depth();
        else
          return _next.depth() + 2;
      }
      
      State next(int ch)
      {
        switch (_state) {
        case TYPE:
          return nextObject(ch);
  
        case COUNT:
          return nextObject(ch);
  
        case FIELD:
          if (_count == 0) {
            println("] */");
            _next.printIndent(0);
  
            return _next.nextObject(ch);
          }
          else
            return nextObject(ch);
  
        default:
          throw new IllegalStateException();
        }
      }
    }
    
    class ObjectState extends State {
      private static final int TYPE = 0;
      private static final int FIELD = 1;
  
      private int _refId;
  
      private int _state;
      private ObjectDef _def;
      private int _count;
      private int _fieldDepth;
  
      ObjectState(State next, int refId)
      {
        super(next);
  
        _refId = refId;
        _state = TYPE;
      }
  
      ObjectState(State next, int refId, int def)
      {
        super(next);
  
        _refId = refId;
        _state = FIELD;
  
        if (def < 0 || _objectDefList.size() <= def) {
          log.warning(this + " " + def + " is an unknown object type");
          
          println(this + " object unknown  (#" + _refId + ")");
        }
  
        _def = _objectDefList.get(def);
        
        if (_isObject)
          println();
  
        println("object " + _def.getType() + " (#" + _refId + ")");
      }
  
      @Override
      boolean isShift(Object value)
      {
        if (_state == TYPE)
          return true;
        else
          return false;
      }
  
      @Override
      State shift(Object object)
      {
        if (_state == TYPE) {
          int def = (Integer) object;
  
          _def = _objectDefList.get(def);
  
          println("object " + _def.getType() + " (#" + _refId + ")");
  
          _state = FIELD;
  
          if (_def.getFields().size() == 0)
            return _next;
        }
  
        return this;
      }
  
      @Override
      int depth()
      {
        if (_state <= TYPE)
          return _next.depth();
        else
          return _fieldDepth;
      }
      
      State next(int ch)
      {
        switch (_state) {
        case TYPE:
          return nextObject(ch);
  
        case FIELD:
          if (_def.getFields().size() <= _count)
            return _next.next(ch);
  
          _fieldDepth = _next.depth() + 2;
          println();
          print(_def.getFields().get(_count++) + ": ");
  
          _fieldDepth = _column;
  
          _isObject = false;
          return nextObject(ch);
  
        default:
          throw new IllegalStateException();
        }
      }
    }
    
    class ListState1 extends State1 {
      private static final int TYPE = 0;
      private static final int LENGTH = 1;
      private static final int VALUE = 2;
  
      private int _refId;
  
      private int _state;
      private int _count;
      private int _valueDepth;
  
      ListState1(State next, int refId)
      {
        super(next);
        
        _refId = refId;
        
        _state = TYPE;
      }
  
      @Override
      boolean isShift(Object value)
      {
        return _state == TYPE || _state == LENGTH;
      }
  
      @Override
      State shift(Object object)
      {
        if (_state == TYPE) {
          Object type = object;
  
          if (type instanceof String) {
            _typeDefList.add((String) type);
          }
          else if (object instanceof Integer) {
            int index = (Integer) object;
  
            if (index >= 0 && index < _typeDefList.size())
              type = _typeDefList.get(index);
            else
              type = "type-unknown(" + index + ")";
          }
  
          printObject("list " + type + "(#" + _refId + ")");
        
          _state = VALUE;
        
          return this;
        }
        else if (_state == LENGTH) {
          _state = VALUE;
  
          return this;
        }
        else
          return this;
      }
  
      @Override
      int depth()
      {
        if (_state <= LENGTH)
          return _next.depth();
        else if (_state == VALUE)
          return _valueDepth;
        else
          return _next.depth() + 2;
      }
      
      State next(int ch)
      {
        switch (_state) {
        case TYPE:
          if (ch == 'z') {
            printObject("list (#" + _refId + ")");
  
            return _next;
          }
          else if (ch == 't') {
            return new StringState(this, 't', true);
          }
          else {
            printObject("list (#" + _refId + ")");
            printObject("  " + _count++ + ": ");
            _valueDepth = _column;
            _isObject = false;
            _state = VALUE;
  
            return nextObject(ch);
          }
  
        case VALUE:
          if (ch == 'z') {
            if (_count > 0)
              println();
  
            return _next;
          }
          else {
            _valueDepth = _next.depth() + 2;
            println();
            printObject(_count++ + ": ");
            _valueDepth = _column;
            _isObject = false;
  
            return nextObject(ch);
          }
  
        default:
          throw new IllegalStateException();
        }
      }
    }
    
    class ListState extends State {
      private static final int TYPE = 0;
      private static final int LENGTH = 1;
      private static final int VALUE = 2;
  
      private int _refId;
  
      private int _state;
      private int _count;
      private int _valueDepth;
  
      ListState(State next, int refId, boolean isType)
      {
        super(next);
        
        _refId = refId;
        
        if (isType)
          _state = TYPE;
        else {
          printObject("list (#" + _refId + ")");
          _state = VALUE;
        }
      }
  
      @Override
      boolean isShift(Object value)
      {
        return _state == TYPE || _state == LENGTH;
      }
  
      @Override
      State shift(Object object)
      {
        if (_state == TYPE) {
          Object type = object;
  
          if (type instanceof String) {
            _typeDefList.add((String) type);
          }
          else if (object instanceof Integer) {
            int index = (Integer) object;
  
            if (index >= 0 && index < _typeDefList.size())
              type = _typeDefList.get(index);
            else
              type = "type-unknown(" + index + ")";
          }
  
          printObject("list " + type + "(#" + _refId + ")");
        
          _state = VALUE;
        
          return this;
        }
        else if (_state == LENGTH) {
          _state = VALUE;
  
          return this;
        }
        else
          return this;
      }
  
      @Override
      int depth()
      {
        if (_state <= LENGTH)
          return _next.depth();
        else if (_state == VALUE)
          return _valueDepth;
        else
          return _next.depth() + 2;
      }
      
      State next(int ch)
      {
        switch (_state) {
        case TYPE:
          return nextObject(ch);
  
        case VALUE:
          if (ch == 'Z') {
            if (_count > 0)
              println();
  
            return _next;
          }
          else {
            _valueDepth = _next.depth() + 2;
            println();
            printObject(_count++ + ": ");
            _valueDepth = _column;
            _isObject = false;
  
            return nextObject(ch);
          }
  
        default:
          throw new IllegalStateException();
        }
      }
    }
    
    class CompactListState extends State {
      private static final int TYPE = 0;
      private static final int LENGTH = 1;
      private static final int VALUE = 2;
  
      private int _refId;
  
      private boolean _isTyped;
      private boolean _isLength;
  
      private int _state;
      private int _length;
      private int _count;
      private int _valueDepth;
  
      CompactListState(State next, int refId, boolean isTyped)
      {
        super(next);
  
        _isTyped = isTyped;
        _refId = refId;
        
        if (isTyped)
          _state = TYPE;
        else
          _state = LENGTH;
      }
  
      CompactListState(State next, int refId, boolean isTyped, int length)
      {
        super(next);
  
        _isTyped = isTyped;
        _refId = refId;
        _length = length;
  
        _isLength = true;
        
        if (isTyped)
          _state = TYPE;
        else {
          printObject("list (#" + _refId + ")");
  
          _state = VALUE;
        }
      }
  
      @Override
      boolean isShift(Object value)
      {
        return _state == TYPE || _state == LENGTH;
      }
  
      @Override
      State shift(Object object)
      {
        if (_state == TYPE) {
          Object type = object;
  
          if (object instanceof Integer) {
            int index = (Integer) object;
  
            if (index >= 0 && index < _typeDefList.size())
              type = _typeDefList.get(index);
            else
              type = "type-unknown(" + index + ")";
          }
          else if (object instanceof String)
            _typeDefList.add((String) object);
  
          printObject("list " + type + " (#" + _refId + ")");
  
          if (_isLength) {
            _state = VALUE;
  
            if (_length == 0)
              return _next;
          }
          else
            _state = LENGTH;
        
          return this;
        }
        else if (_state == LENGTH) {
          _length = (Integer) object;
  
          if (! _isTyped)
            printObject("list (#" + _refId + ")");
  
          _state = VALUE;
  
          if (_length == 0)
            return _next;
          else
            return this;
        }
        else
          return this;
      }
  
      @Override
      int depth()
      {
        if (_state <= LENGTH)
          return _next.depth();
        else if (_state == VALUE)
          return _valueDepth;
        else
          return _next.depth() + 2;
      }
      
      State next(int ch)
      {
        switch (_state) {
        case TYPE:
          return nextObject(ch);
  
        case LENGTH:
          return nextObject(ch);
  
        case VALUE:
          if (_length <= _count)
            return _next.next(ch);
          else {
            _valueDepth = _next.depth() + 2;
            println();
            printObject(_count++ + ": ");
            _valueDepth = _column;
            _isObject = false;
  
            return nextObject(ch);
          }
  
        default:
          throw new IllegalStateException();
        }
      }
    }
    
    class Hessian2State extends State {
      private static final int MAJOR = 0;
      private static final int MINOR = 1;
  
      private int _state;
      private int _major;
      private int _minor;
  
      Hessian2State(State next)
      {
        super(next);
      }
  
      int depth()
      {
        return _next.depth() + 2;
      }
      
      State next(int ch)
      {
        switch (_state) {
        case MAJOR:
          _major = ch;
          _state = MINOR;
          return this;
  
        case MINOR:
          _minor = ch;
          println(-2, "Hessian " + _major + "." + _minor);
          return _next;
  
        default:
          throw new IllegalStateException();
        }
      }
    }
    
    class CallState1 extends State1 {
      private static final int MAJOR = 0;
      private static final int MINOR = 1;
      private static final int HEADER = 2;
      private static final int METHOD = 3;
      private static final int VALUE = 4;
      private static final int ARG = 5;
  
      private int _state;
      private int _major;
      private int _minor;
  
      CallState1(State next)
      {
        super(next);
      }
  
      int depth()
      {
        return _next.depth() + 2;
      }
      
      State next(int ch)
      {
        switch (_state) {
        case MAJOR:
          _major = ch;
          _state = MINOR;
          return this;
  
        case MINOR:
          _minor = ch;
          _state = HEADER;
          println(-2, "call " + _major + "." + _minor);
          return this;
  
        case HEADER:
          if (ch == 'H') {
            println();
            print("header ");
            _isObject = false;
            _state = VALUE;
            return new StringState(this, 'H', true);
          }
           else if (ch == 'm') {
            println();
            print("method ");
            _isObject = false;
            _state = ARG;
            return new StringState(this, 'm', true);
          }
          else {
            println((char) ch + ": unexpected char");
            return popStack();
          }
  
        case VALUE:
          print(" => ");
          _isObject = false;
          _state = HEADER;
          return nextObject(ch);
  
        case ARG:
          if (ch == 'z') {
            println();
            return _next;
          }
          else
            return nextObject(ch);
  
        default:
          throw new IllegalStateException();
        }
      }
    }
    
    class Call2State extends State {
      private static final int METHOD = 0;
      private static final int COUNT = 1;
      private static final int ARG = 2;
  
      private int _state = METHOD;
      private int _i;
      private int _count;
  
      Call2State(State next)
      {
        super(next);
      }
  
      int depth()
      {
        return _next.depth() + 5;
      }
  
      @Override
      boolean isShift(Object value)
      {
        return _state != ARG;
      }
  
      @Override
      State shift(Object object)
      {
        if (_state == METHOD) {
          println(-5, "Call " + object);
  
          _state = COUNT;
          return this;
        }
        else if (_state == COUNT) {
          Integer count = (Integer) object;
  
          _count = count;
        
          _state = ARG;
  
          if (_count == 0) {
            return _next;
          }
          else
            return this;
        }
        else {
          return this;
        }
      }
  
      @Override
      State next(int ch)
      {
        switch (_state) {
        case COUNT:
          return nextObject(ch);
  
        case METHOD:
          return nextObject(ch);
  
        case ARG:
          if (_count <= _i) {
            println();
            return _next.next(ch);
          }
          else {
            println();
            print(-3, _i++ + ": ");
  
            return nextObject(ch);
          }
  
        default:
          throw new IllegalStateException();
        }
      }
    }
    
    class ReplyState1 extends State1 {
      private static final int MAJOR = 0;
      private static final int MINOR = 1;
      private static final int HEADER = 2;
      private static final int VALUE = 3;
      private static final int END = 4;
  
      private int _state;
      private int _major;
      private int _minor;
  
      ReplyState1(State next)
      {
        _next = next;
      }
  
      int depth()
      {
        return _next.depth() + 2;
      }
      
      State next(int ch)
      {
        switch (_state) {
        case MAJOR:
          if (ch == 't' || ch == 'S')
            return new RemoteState(this).next(ch);
  
          _major = ch;
          _state = MINOR;
          return this;
  
        case MINOR:
          _minor = ch;
          _state = HEADER;
          println(-2, "reply " + _major + "." + _minor);
          return this;
  
        case HEADER:
          if (ch == 'H') {
            _state = VALUE;
            return new StringState(this, 'H', true);
          }
          else if (ch == 'f') {
            print("fault ");
            _isObject = false;
            _state = END;
            return new MapState(this, 0);
          }
           else {
            _state = END;
            return nextObject(ch);
          }
  
        case VALUE:
          _state = HEADER;
          return nextObject(ch);
  
        case END:
          println();
          if (ch == 'z') {
            return _next;
          }
          else
            return _next.next(ch);
  
        default:
          throw new IllegalStateException();
        }
      }
    }
    
    class Reply2State extends State {
      Reply2State(State next)
      {
        super(next);
  
        println(-2, "Reply");
      }
  
      int depth()
      {
        return _next.depth() + 2;
      }
  
      @Override
      State next(int ch)
      {
        if (ch < 0) {
          println();
          return _next;
        }
        else {
          return nextObject(ch);
        }
      }
    }
    
    class Fault2State extends State {
      Fault2State(State next)
      {
        super(next);
  
        println(-2, "Fault");
      }
  
      int depth()
      {
        return _next.depth() + 2;
      }
  
      @Override
      State next(int ch)
      {
        return nextObject(ch);
      }
    }
    
    class IndirectState extends State {
      IndirectState(State next)
      {
        super(next);
      }
  
      boolean isShift(Object object)
      {
        return _next.isShift(object);
      }
  
      State shift(Object object)
      {
        return _next.shift(object);
      }
      
      State next(int ch)
      {
        return nextObject(ch);
      }
    }
    
    class RemoteState extends State {
      private static final int TYPE = 0;
      private static final int VALUE = 1;
      private static final int END = 2;
  
      private int _state;
      private int _major;
      private int _minor;
  
      RemoteState(State next)
      {
        super(next);
      }
      
      @Override
      State next(int ch)
      {
        switch (_state) {
        case TYPE:
          println(-1, "remote");
          if (ch == 't') {
            _state = VALUE;
            return new StringState(this, 't', false);
          }
          else {
            _state = END;
            return nextObject(ch);
          }
  
        case VALUE:
          _state = END;
          return _next.nextObject(ch);
  
        case END:
          return _next.next(ch);
  
        default:
          throw new IllegalStateException();
        }
      }
    }
    
    class StreamingState extends State {
      private long _length;
      private int _metaLength;
      private boolean _isLast;
      private boolean _isFirst = true;
      
      private boolean _isLengthState;
  
      private State _childState;
  
      StreamingState(State next, boolean isLast)
      {
        super(next);
  
        _isLast = isLast;
        _childState = new InitialState();
      }
      
      State next(int ch)
      {
        if (_metaLength > 0) {
          _length = 256 * _length + ch;
          _metaLength--;
          
          if (_metaLength == 0 && _isFirst) {
            if (_isLast)
              println(-1, "--- packet-start(" + _length + ")");
            else
              println(-1, "--- packet-start(fragment)");
            _isFirst = false;
          }
          
          return this;
        }
        
        if (_length > 0) {
          _length--;
          _childState = _childState.next(ch);
          
          return this;
        }
        
        if (! _isLengthState) {
          _isLengthState = true;
          
          if (_isLast) {
            println(-1, "");
            println(-1, "--- packet-end");
            _refId = 0;
            
            _isFirst = true;
          }
          
          _isLast = (ch & 0x80) == 0x00;
          _isLengthState = true;
        }
        else {
          _isLengthState = false;
          _length = (ch & 0x7f);
          
          if (_length == 0x7e) {
            _length = 0;
            _metaLength = 2;
          }
          else if (_length == 0x7f) {
            _length = 0;
            _metaLength = 8;
          }
          else {
            if (_isFirst) {
              if (_isLast)
                println(-1, "--- packet-start(" + _length + ")");
              else
                println(-1, "--- packet-start(fragment)");
              _isFirst = false;
            }
          }
        }
        
        return this;
      }
    }
  
    static class ObjectDef {
      private String _type;
      private ArrayList<String> _fields;
  
      ObjectDef(String type, ArrayList<String> fields)
      {
        _type = type;
        _fields = fields;
      }
  
      String getType()
      {
        return _type;
      }
  
      ArrayList<String> getFields()
      {
        return _fields;
      }
    }
  }
  