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