blob: 7bf7bf5d89f361a2e856459890c8b72cb41ce79d [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2015 IBM Corporation and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* IBM Corporation - initial API and implementation
* Francis Lynch (Wind River) - [305718] Allow reading snapshot into renamed project
*******************************************************************************/
package org.eclipse.core.internal.watson;
import java.io.*;
import org.eclipse.core.internal.dtree.DataTreeReader;
import org.eclipse.core.internal.dtree.IDataFlattener;
import org.eclipse.core.internal.utils.Messages;
import org.eclipse.core.runtime.*;
/** <code>ElementTreeReader</code> is the standard implementation
* of an element tree serialization reader.
*
* <p>Subclasses of this reader read can handle current and various
* known old formats of a saved element tree, and dispatch internally
* to an appropriate reader.
*
* <p>The reader has an <code>IElementInfoFactory</code>,
* which it consults for the schema and for creating
* and reading element infos.
*
* <p>Element tree readers are thread-safe; several
* threads may share a single reader provided, of course,
* that the <code>IElementInfoFactory</code> is thread-safe.
*/
public class ElementTreeReader {
/** The element info factory.
*/
protected IElementInfoFlattener elementInfoFlattener;
/**
* For reading and writing delta trees
*/
protected DataTreeReader dataTreeReader;
/**
* Constructs a new element tree reader that works for
* the given element info flattener.
*/
public ElementTreeReader(final IElementInfoFlattener factory) {
Assert.isNotNull(factory);
elementInfoFlattener = factory;
/* wrap the IElementInfoFlattener in an IDataFlattener */
IDataFlattener f = new IDataFlattener() {
@Override
public void writeData(IPath path, Object data, DataOutput output) {
//not needed
}
@Override
public Object readData(IPath path, DataInput input) throws IOException {
//never read the root node of an ElementTree
//this node is reserved for the parent backpointer
if (!Path.ROOT.equals(path))
return factory.readElement(path, input);
return null;
}
};
dataTreeReader = new DataTreeReader(f);
}
/**
* Returns the appropriate reader for the given version.
*/
public ElementTreeReader getReader(int formatVersion) throws IOException {
if (formatVersion == 1)
return new ElementTreeReaderImpl_1(elementInfoFlattener);
throw new IOException(Messages.watson_unknown);
}
/**
* Reads an element tree delta from the input stream, and
* reconstructs it as a delta on the given tree.
*/
public ElementTree readDelta(ElementTree completeTree, DataInput input) throws IOException {
/* Dispatch to the appropriate reader. */
ElementTreeReader realReader = getReader(readNumber(input));
return realReader.readDelta(completeTree, input);
}
/**
* Reads a chain of ElementTrees from the given input stream.
* @return A chain of ElementTrees, where the first tree in the list is
* complete, and all other trees are deltas on the previous tree in the list.
*/
public ElementTree[] readDeltaChain(DataInput input) throws IOException {
return readDeltaChain(input, ""); //$NON-NLS-1$
}
/**
* Reads a chain of ElementTrees from the given input stream.
* @param input the input stream to read from.
* @param newProjectName a new name to use for the root node of the
* tree being read, or the empty String ("") to read the tree
* from the given input unchanged.
* @return A chain of ElementTrees, where the first tree in the list is
* complete, and all other trees are deltas on the previous tree in the list.
s */
public ElementTree[] readDeltaChain(DataInput input, String newProjectName) throws IOException {
/* Dispatch to the appropriate reader. */
ElementTreeReader realReader = getReader(readNumber(input));
return realReader.readDeltaChain(input, newProjectName);
}
/**
* Reads an integer stored in compact format. Numbers between
* 0 and 254 inclusive occupy 1 byte; other numbers occupy 5 bytes,
* the first byte being 0xff and the next 4 bytes being the standard
* representation of an int.
*/
protected static int readNumber(DataInput input) throws IOException {
byte b = input.readByte();
int number = (b & 0xff); // not a no-op! converts unsigned byte to int
if (number == 0xff) { // magic escape value
number = input.readInt();
}
return number;
}
/**
* Reads an element tree from the input stream and returns it.
* This method actually just dispatches to the appropriate reader
* depending on the stream version id.
*/
public ElementTree readTree(DataInput input) throws IOException {
return readTree(input, ""); //$NON-NLS-1$
}
/**
* Reads an element tree from the input stream and returns it.
* This method actually just dispatches to the appropriate reader
* depending on the stream version id.
* @param input the input stream to read from.
* @param newProjectName a new name to use for the root node of the
* tree being read, or the empty String ("") to read the tree
* from the given input unchanged.
* @return the requested ElementTree.
*/
public ElementTree readTree(DataInput input, String newProjectName) throws IOException {
/* Dispatch to the appropriate reader. */
ElementTreeReader realReader = getReader(readNumber(input));
return realReader.readTree(input, newProjectName);
}
}