platform35/org.eclipse.core.resources/src/org/eclipse/core/internal/dtree/DataTreeWriter.java
changeset 40 eb3c938c7fef
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/platform35/org.eclipse.core.resources/src/org/eclipse/core/internal/dtree/DataTreeWriter.java	Thu Jul 30 11:56:23 2009 -0500
@@ -0,0 +1,184 @@
+/*******************************************************************************
+ * 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);
+	}
+}