1 /*******************************************************************************
2  * Copyright (c) 2000, 2015 IBM Corporation and others.
3  *
4  * This program and the accompanying materials
5  * are made available under the terms of the Eclipse Public License 2.0
6  * which accompanies this distribution, and is available at
7  * https://www.eclipse.org/legal/epl-2.0/
8  *
9  * SPDX-License-Identifier: EPL-2.0
10  *
11  * Contributors:
12  *     IBM Corporation - initial API and implementation
13  * Francis Lynch (Wind River) - [305718] Allow reading snapshot into renamed project
14  *******************************************************************************/
15 package org.eclipse.core.internal.watson;
16 
17 import java.io.*;
18 import org.eclipse.core.internal.dtree.DataTreeReader;
19 import org.eclipse.core.internal.dtree.IDataFlattener;
20 import org.eclipse.core.internal.utils.Messages;
21 import org.eclipse.core.runtime.*;
22 
23 /** <code>ElementTreeReader</code> is the standard implementation
24  * of an element tree serialization reader.
25  *
26  * <p>Subclasses of this reader read can handle current and various
27  * known old formats of a saved element tree, and dispatch internally
28  * to an appropriate reader.
29  *
30  * <p>The reader has an <code>IElementInfoFactory</code>,
31  * which it consults for the schema and for creating
32  * and reading element infos.
33  *
34  * <p>Element tree readers are thread-safe; several
35  * threads may share a single reader provided, of course,
36  * that the <code>IElementInfoFactory</code> is thread-safe.
37  */
38 public class ElementTreeReader {
39 	/** The element info factory.
40 	 */
41 	protected IElementInfoFlattener elementInfoFlattener;
42 
43 	/**
44 	 * For reading and writing delta trees
45 	 */
46 	protected DataTreeReader dataTreeReader;
47 
48 	/**
49 	 * Constructs a new element tree reader that works for
50 	 * the given element info flattener.
51 	 */
ElementTreeReader(final IElementInfoFlattener factory)52 	public ElementTreeReader(final IElementInfoFlattener factory) {
53 		Assert.isNotNull(factory);
54 		elementInfoFlattener = factory;
55 
56 		/* wrap the IElementInfoFlattener in an IDataFlattener */
57 		IDataFlattener f = new IDataFlattener() {
58 			@Override
59 			public void writeData(IPath path, Object data, DataOutput output) {
60 				//not needed
61 			}
62 
63 			@Override
64 			public Object readData(IPath path, DataInput input) throws IOException {
65 				//never read the root node of an ElementTree
66 				//this node is reserved for the parent backpointer
67 				if (!Path.ROOT.equals(path))
68 					return factory.readElement(path, input);
69 				return null;
70 			}
71 		};
72 		dataTreeReader = new DataTreeReader(f);
73 	}
74 
75 	/**
76 	 * Returns the appropriate reader for the given version.
77 	 */
getReader(int formatVersion)78 	public ElementTreeReader getReader(int formatVersion) throws IOException {
79 		if (formatVersion == 1)
80 			return new ElementTreeReaderImpl_1(elementInfoFlattener);
81 		throw new IOException(Messages.watson_unknown);
82 	}
83 
84 	/**
85 	 * Reads an element tree delta from the input stream, and
86 	 * reconstructs it as a delta on the given tree.
87 	 */
readDelta(ElementTree completeTree, DataInput input)88 	public ElementTree readDelta(ElementTree completeTree, DataInput input) throws IOException {
89 		/* Dispatch to the appropriate reader. */
90 		ElementTreeReader realReader = getReader(readNumber(input));
91 		return realReader.readDelta(completeTree, input);
92 	}
93 
94 	/**
95 	 * Reads a chain of ElementTrees from the given input stream.
96 	 * @return A chain of ElementTrees, where the first tree in the list is
97 	 * complete, and all other trees are deltas on the previous tree in the list.
98 	 */
readDeltaChain(DataInput input)99 	public ElementTree[] readDeltaChain(DataInput input) throws IOException {
100 		return readDeltaChain(input, ""); //$NON-NLS-1$
101 	}
102 
103 	/**
104 	 * Reads a chain of ElementTrees from the given input stream.
105 	 * @param input the input stream to read from.
106 	 * @param newProjectName a new name to use for the root node of the
107 	 *     tree being read, or the empty String ("") to read the tree
108 	 *     from the given input unchanged.
109 	 * @return A chain of ElementTrees, where the first tree in the list is
110 	 * complete, and all other trees are deltas on the previous tree in the list.
111 	s	 */
readDeltaChain(DataInput input, String newProjectName)112 	public ElementTree[] readDeltaChain(DataInput input, String newProjectName) throws IOException {
113 		/* Dispatch to the appropriate reader. */
114 		ElementTreeReader realReader = getReader(readNumber(input));
115 		return realReader.readDeltaChain(input, newProjectName);
116 	}
117 
118 	/**
119 	 * Reads an integer stored in compact format.  Numbers between
120 	 * 0 and 254 inclusive occupy 1 byte; other numbers occupy 5 bytes,
121 	 * the first byte being 0xff and the next 4 bytes being the standard
122 	 * representation of an int.
123 	 */
readNumber(DataInput input)124 	protected static int readNumber(DataInput input) throws IOException {
125 		byte b = input.readByte();
126 		int number = (b & 0xff); // not a no-op! converts unsigned byte to int
127 
128 		if (number == 0xff) { // magic escape value
129 			number = input.readInt();
130 		}
131 		return number;
132 	}
133 
134 	/**
135 	 * Reads an element tree from the input stream and returns it.
136 	 * This method actually just dispatches to the appropriate reader
137 	 * depending on the stream version id.
138 	 */
readTree(DataInput input)139 	public ElementTree readTree(DataInput input) throws IOException {
140 		return readTree(input, ""); //$NON-NLS-1$
141 	}
142 
143 	/**
144 	 * Reads an element tree from the input stream and returns it.
145 	 * This method actually just dispatches to the appropriate reader
146 	 * depending on the stream version id.
147 	 * @param input the input stream to read from.
148 	 * @param newProjectName a new name to use for the root node of the
149 	 *     tree being read, or the empty String ("") to read the tree
150 	 *     from the given input unchanged.
151 	 * @return the requested ElementTree.
152 	 */
readTree(DataInput input, String newProjectName)153 	public ElementTree readTree(DataInput input, String newProjectName) throws IOException {
154 		/* Dispatch to the appropriate reader. */
155 		ElementTreeReader realReader = getReader(readNumber(input));
156 		return realReader.readTree(input, newProjectName);
157 	}
158 }
159