private void readCapabilities(DataInput in) throws IOException {
    long capabilities = in.readLong();
    long frequentCapabilities = in.readLong();

    for (int i = 0; i < 64; i++) {
      if ((capabilities & (1L << i)) != 0L) node.setCapability(i);
      if ((frequentCapabilities & (1L << i)) != 0L) node.clearCapabilityIsFrequent(i);
    }
  }
  /*
   * NOTE:  This implementation assumes a maximum of 64 capability
   * bits per node class.  If this changes in the future, this
   * implementation will need to be updated.
   */
  private void writeCapabilities(DataOutput out) throws IOException {
    long capabilities = 0;
    long frequentCapabilities = 0;

    for (int i = 0; i < 64; i++) {
      if (node.getCapability(i)) capabilities |= (1L << i);
      if (!(node.getCapabilityIsFrequent(i))) frequentCapabilities |= (1L << i);
    }
    out.writeLong(capabilities);
    out.writeLong(frequentCapabilities);
  }
  /**
   * Create a new State object
   *
   * <p>During Saveing SymbolTableData will have the nodeID and j3dNode fields set
   *
   * <p>During loading SymbolTableData be null, symbol will be created and added to the symbol data
   * during readObject()
   */
  public SceneGraphObjectState(SymbolTableData symbol, Controller control) {
    this.symbol = symbol;
    this.control = control;

    if (symbol != null) {
      this.node = symbol.j3dNode;

      // This consistancy check is for debugging purposes
      // if (symbol.j3dNode==null || symbol.nodeID==0)
      //    throw new RuntimeException( "Bad Symbol in State creation");
    }

    if (node != null) {
      nodeClassName = node.getClass().getName();

      try {
        if (node instanceof com.sun.j3d.utils.scenegraph.io.SceneGraphIO)
          ((com.sun.j3d.utils.scenegraph.io.SceneGraphIO) node)
              .createSceneGraphObjectReferences(control.getSymbolTable());
      } catch (Exception e) {
        System.err.println("Exception in createSceneGraphObjectReferences");
        e.printStackTrace();
      }
    }
  }
  /**
   * DO NOT call symbolTable.addReference in writeObject as this (may) result in a
   * concurrentModificationException.
   *
   * <p>All references should be created in the constructor
   */
  public void writeObject(DataOutput out) throws IOException {
    boolean sgIO = node instanceof com.sun.j3d.utils.scenegraph.io.SceneGraphIO;
    out.writeBoolean(sgIO);
    out.writeInt(symbol.nodeID);

    int nodeClassID = control.getNodeClassID(node);

    out.writeShort(nodeClassID);

    if (nodeClassID == -1) out.writeUTF(nodeClassName);

    writeConstructorParams(out);

    if (sgIO) {
      ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
      DataOutputStream tmpOut = new DataOutputStream(byteStream);
      ((com.sun.j3d.utils.scenegraph.io.SceneGraphIO) node).writeSceneGraphObject(tmpOut);
      tmpOut.close();
      out.writeInt(byteStream.size());
      out.write(byteStream.toByteArray());
    }

    writeUserData(out);
    writeString(node.getName(), out);

    writeCapabilities(out);
  }
  private void writeUserData(DataOutput out) throws IOException {
    Object obj = node.getUserData();
    if (obj != null && !(obj instanceof java.io.Serializable)) {
      System.err.println("UserData is not Serializable and will not be saved");
      obj = null;
    }

    control.writeSerializedData(out, (Serializable) obj);
  }
  public void readObject(DataInput in) throws IOException {

    boolean sgIO = in.readBoolean();
    int nodeID = in.readInt();

    int nodeClassID = in.readShort();

    nodeClassName = null;

    if (nodeClassID == -1) nodeClassName = in.readUTF();

    readConstructorParams(in);

    if (nodeClassID != -1) {
      node = createNode();
      nodeClassName = node.getClass().getName();
    } else node = createNode(nodeClassName);

    if (sgIO) {
      if (control.getCurrentFileVersion() == 1)
        ((com.sun.j3d.utils.scenegraph.io.SceneGraphIO) node).readSceneGraphObject(in);
      else {
        int size = in.readInt();
        if (node instanceof com.sun.j3d.utils.scenegraph.io.SceneGraphIO) {
          byte[] bytes = new byte[size];
          in.readFully(bytes);
          ByteArrayInputStream byteStream = new ByteArrayInputStream(bytes);
          DataInputStream tmpIn = new DataInputStream(byteStream);
          ((com.sun.j3d.utils.scenegraph.io.SceneGraphIO) node).readSceneGraphObject(tmpIn);
          tmpIn.close();
        } else {
          in.skipBytes(size);
        }
      }
    }

    symbol = control.getSymbolTable().createSymbol(this, node, nodeID);
    readUserData(in);
    if (control.getCurrentFileVersion() > 2) {
      node.setName(readString(in));
    }

    readCapabilities(in);
  }
  private void readUserData(DataInput in) throws IOException {

    node.setUserData(control.readSerializedData(in));
  }