/******************************************************************************* * Copyright (c) 2000, 2005 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * IBM Corporation - initial API and implementation *******************************************************************************/ package org.eclipse.core.internal.dtree; import java.io.DataOutput; import java.io.IOException; import org.eclipse.core.runtime.*; /** * Class for writing a single data tree (no parents) to an output stream. */ public class DataTreeWriter { /** * Callback for serializing tree data */ protected IDataFlattener flatener; /** * The stream to write output to */ protected DataOutput output; /** * Constant representing infinite recursion depth */ public static final int D_INFINITE = -1; /** * Creates a new DeltaTreeWriter. */ public DataTreeWriter(IDataFlattener f) { flatener = f; } /** * Writes the subtree rooted at the given node. * @param node The subtree to write. * @param path The path of the current node. * @param depth The depth of the subtree to write. */ protected void writeNode(AbstractDataTreeNode node, IPath path, int depth) throws IOException { int type = node.type(); /* write the node name */ String name = node.getName(); if (name == null) { name = ""; //$NON-NLS-1$ } output.writeUTF(name); /* write the node type */ writeNumber(type); /* maybe write the data */ if (node.hasData()) { Object data = node.getData(); /** * Write a flag indicating whether or not the data field is null. * Zero means data is null, non-zero means data is present */ if (data == null) { writeNumber(0); } else { writeNumber(1); flatener.writeData(path, node.getData(), output); } } /* maybe write the children */ if (depth > 0 || depth == D_INFINITE) { AbstractDataTreeNode[] children = node.getChildren(); /* write the number of children */ writeNumber(children.length); /* write the children */ int newDepth = (depth == D_INFINITE) ? D_INFINITE : depth - 1; for (int i = 0, imax = children.length; i < imax; i++) { writeNode(children[i], path.append(children[i].getName()), newDepth); } } else { /* write the number of children */ writeNumber(0); } } /** * Writes an integer in a compact format biased towards * small non-negative numbers. Numbers between * 0 and 254 inclusive occupy 1 byte; other numbers occupy 5 bytes. */ protected void writeNumber(int number) throws IOException { if (number >= 0 && number < 0xff) { output.writeByte(number); } else { output.writeByte(0xff); output.writeInt(number); } } /** * Writes a single node to the output. Does not recurse * on child nodes, and does not write the number of children. */ protected void writeSingleNode(AbstractDataTreeNode node, IPath path) throws IOException { /* write the node name */ String name = node.getName(); if (name == null) { name = ""; //$NON-NLS-1$ } output.writeUTF(name); /* write the node type */ writeNumber(node.type()); /* maybe write the data */ if (node.hasData()) { Object data = node.getData(); /** * Write a flag indicating whether or not the data field is null. * Zero means data is null, non-zero means data is present */ if (data == null) { writeNumber(0); } else { writeNumber(1); flatener.writeData(path, node.getData(), output); } } } /** * Writes the given AbstractDataTree to the given stream. This * writes a single DataTree or DeltaDataTree, ignoring parent * trees. * * @param path Only writes data for the subtree rooted at the given path, and * for all nodes directly between the root and the subtree. * @param depth In the subtree rooted at the given path, * only write up to this depth. A depth of infinity is given * by the constant D_INFINITE. */ public void writeTree(AbstractDataTree tree, IPath path, int depth, DataOutput output) throws IOException { this.output = output; /* tunnel down relevant path */ AbstractDataTreeNode node = tree.getRootNode(); IPath currentPath = Path.ROOT; String[] segments = path.segments(); for (int i = 0; i < segments.length; i++) { String nextSegment = segments[i]; /* write this node to the output */ writeSingleNode(node, currentPath); currentPath = currentPath.append(nextSegment); node = node.childAtOrNull(nextSegment); /* write the number of children for this node */ if (node != null) { writeNumber(1); } else { /* can't navigate down the path, just give up with what we have so far */ writeNumber(0); return; } } Assert.isTrue(currentPath.equals(path), "dtree.navigationError"); //$NON-NLS-1$ /* recursively write the subtree we're interested in */ writeNode(node, path, depth); } }