/*******************************************************************************
* Copyright (c) 2009, 2015 Wind River Systems, Inc. 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:
* Markus Schorn - initial API and implementation
* Sergey Prigogin (Google)
*******************************************************************************/
package org.eclipse.cdt.internal.core.pdom.dom;
import org.eclipse.cdt.core.CCorePlugin;
import org.eclipse.cdt.core.dom.ast.ASTTypeUtil;
import org.eclipse.cdt.core.dom.ast.IBinding;
import org.eclipse.cdt.core.dom.ast.ISemanticProblem;
import org.eclipse.cdt.core.dom.ast.IType;
import org.eclipse.cdt.core.dom.ast.ITypedef;
import org.eclipse.cdt.core.dom.ast.IValue;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateArgument;
import org.eclipse.cdt.internal.core.dom.parser.CStringValue;
import org.eclipse.cdt.internal.core.dom.parser.CompositeValue;
import org.eclipse.cdt.internal.core.dom.parser.DependentValue;
import org.eclipse.cdt.internal.core.dom.parser.FloatingPointValue;
import org.eclipse.cdt.internal.core.dom.parser.ISerializableType;
import org.eclipse.cdt.internal.core.dom.parser.ITypeMarshalBuffer;
import org.eclipse.cdt.internal.core.dom.parser.IntegralValue;
import org.eclipse.cdt.internal.core.dom.parser.ProblemBinding;
import org.eclipse.cdt.internal.core.dom.parser.ProblemType;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPTemplateNonTypeArgument;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPTemplateTypeArgument;
import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPEvaluation;
import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPExecution;
import org.eclipse.cdt.internal.core.pdom.db.Database;
import org.eclipse.core.runtime.CoreException;
/**
* For marshalling types to byte arrays.
*/
public final class TypeMarshalBuffer implements ITypeMarshalBuffer {
public static final byte[] EMPTY = new byte[Database.TYPE_SIZE];
public static final byte NULL_TYPE = 0x00;
public static final byte INDIRECT_TYPE = 0x1F;
public static final byte BINDING_TYPE = 0x1E;
public static final byte UNSTORABLE_TYPE = 0x1D;
public static final IType UNSTORABLE_TYPE_PROBLEM = new ProblemType(ISemanticProblem.TYPE_NOT_PERSISTED);
private final PDOMLinkage fLinkage;
private int fPos;
private byte[] fBuffer;
/**
* Constructor for output buffer.
*/
public TypeMarshalBuffer(PDOMLinkage linkage) {
fLinkage= linkage;
}
/**
* Constructor for input buffer.
*/
public TypeMarshalBuffer(PDOMLinkage linkage, byte[] data) {
fLinkage= linkage;
fBuffer= data;
}
public int getPosition() {
return fPos;
}
public void setPosition(int pos) {
assert 0 <= pos && pos <= fPos;
fPos = pos;
}
public byte[] getBuffer() {
return fBuffer;
}
@Override
public void marshalBinding(IBinding binding) throws CoreException {
if (binding instanceof ISerializableType) {
((ISerializableType) binding).marshal(this);
} else if (binding == null) {
putShort(NULL_TYPE);
} else {
PDOMNode pb= fLinkage.addTypeBinding(binding);
if (pb == null && binding instanceof ITypedef) {
// Since typedef defined in a local scope cannot be stored in the index,
// store the target type instead.
IType type = ((ITypedef) binding).getType();
if (type instanceof ISerializableType) {
((ISerializableType) type).marshal(this);
return;
} else if (type instanceof IBinding) {
pb = fLinkage.addTypeBinding((IBinding) type);
}
}
if (pb == null) {
putShort(UNSTORABLE_TYPE);
} else {
putShort(BINDING_TYPE);
putByte((byte) 0);
putRecordPointer(pb.getRecord());
}
}
}
@Override
public IBinding unmarshalBinding() throws CoreException {
int oldPos = fPos;
short firstBytes = getShort();
if (firstBytes == BINDING_TYPE) {
fPos += 1;
long rec= getRecordPointer();
return (IBinding) PDOMNode.load(fLinkage.getPDOM(), rec);
} else if (firstBytes == NULL_TYPE) {
return null;
} else if (firstBytes == UNSTORABLE_TYPE) {
return new ProblemBinding(null, ISemanticProblem.TYPE_NOT_PERSISTED);
}
fPos = oldPos; // fLinkage.unmarshalBinding() will read firstBytes again
return fLinkage.unmarshalBinding(this);
}
@Override
public void marshalType(IType type) throws CoreException {
if (type instanceof ISerializableType) {
((ISerializableType) type).marshal(this);
} else if (type == null) {
putShort(NULL_TYPE);
} else if (type instanceof IBinding) {
marshalBinding((IBinding) type);
} else {
assert false : "Cannot serialize " + ASTTypeUtil.getType(type) + " (" + type.getClass().getName() + ")"; //$NON-NLS-1$//$NON-NLS-2$//$NON-NLS-3$
putShort(UNSTORABLE_TYPE);
}
}
@Override
public IType unmarshalType() throws CoreException {
int oldPos = fPos;
short firstBytes = getShort();
if (firstBytes == BINDING_TYPE) {
fPos += 1;
long rec= getRecordPointer();
return (IType) PDOMNode.load(fLinkage.getPDOM(), rec);
} else if (firstBytes == NULL_TYPE) {
return null;
} else if (firstBytes == UNSTORABLE_TYPE) {
return UNSTORABLE_TYPE_PROBLEM;
}
fPos = oldPos; // fLinkage.unmarshalType() will read firstBytes again
return fLinkage.unmarshalType(this);
}
@Override
public void marshalEvaluation(ICPPEvaluation eval, boolean includeValues) throws CoreException {
if (eval == null) {
putShort(NULL_TYPE);
} else {
eval.marshal(this, includeValues);
}
}
@Override
public void marshalExecution(ICPPExecution exec, boolean includeValue) throws CoreException {
if (exec == null) {
putShort(NULL_TYPE);
} else {
exec.marshal(this, includeValue);
}
}
@Override
public ICPPEvaluation unmarshalEvaluation() throws CoreException {
return fLinkage.unmarshalEvaluation(this);
}
@Override
public ICPPExecution unmarshalExecution() throws CoreException {
return fLinkage.unmarshalExecution(this);
}
@Override
public void marshalValue(IValue value) throws CoreException {
if(value != null) {
value.marshal(this);
} else {
putShort(NULL_TYPE);
}
}
@Override
public IValue unmarshalValue() throws CoreException {
short firstBytes= getShort();
if (firstBytes == TypeMarshalBuffer.NULL_TYPE)
return null;
switch ((firstBytes & ITypeMarshalBuffer.KIND_MASK)) {
case ITypeMarshalBuffer.INTEGRAL_VALUE:
return IntegralValue.unmarshal(firstBytes, this);
case ITypeMarshalBuffer.FLOATING_POINT_VALUE:
return FloatingPointValue.unmarshal(firstBytes, this);
case ITypeMarshalBuffer.C_STRING_VALUE:
return CStringValue.unmarshal(firstBytes, this);
case ITypeMarshalBuffer.COMPOSITE_VALUE:
return CompositeValue.unmarshal(firstBytes, this);
case ITypeMarshalBuffer.DEPENDENT_VALUE:
return DependentValue.unmarshal(firstBytes, this);
}
throw new CoreException(CCorePlugin.createStatus("Cannot unmarshal a value, first bytes=" + firstBytes)); //$NON-NLS-1$
}
@Override
public void marshalTemplateArgument(ICPPTemplateArgument arg) throws CoreException {
if (arg.isNonTypeValue()) {
putShort(VALUE);
arg.getNonTypeEvaluation().marshal(this, true);
} else {
final IType typeValue = arg.getTypeValue();
final IType originalTypeValue = arg.getOriginalTypeValue();
marshalType(typeValue);
if (typeValue != originalTypeValue) {
marshalType(originalTypeValue);
} else {
marshalType(null);
}
}
}
@Override
public ICPPTemplateArgument unmarshalTemplateArgument() throws CoreException {
int oldPos = fPos;
short firstBytes = getShort();
if (firstBytes == VALUE) {
return new CPPTemplateNonTypeArgument(unmarshalEvaluation(), null);
} else {
fPos = oldPos;
IType type = unmarshalType();
IType originalType = unmarshalType();
if (originalType == null)
originalType= type;
return new CPPTemplateTypeArgument(type, originalType);
}
}
private void request(int i) {
if (fBuffer == null) {
if (i <= Database.TYPE_SIZE) {
fBuffer= new byte[Database.TYPE_SIZE];
} else {
fBuffer= new byte[i];
}
} else {
final int bufLen = fBuffer.length;
int needLen = fPos + i;
if (needLen > bufLen) {
needLen= Math.max(needLen, 2 * bufLen);
byte[] newBuffer= new byte[needLen];
System.arraycopy(fBuffer, 0, newBuffer, 0, fPos);
fBuffer= newBuffer;
}
}
}
@Override
public void putByte(byte b) {
request(1);
fBuffer[fPos++]= b;
}
@Override
public int getByte() throws CoreException {
if (fPos + 1 > fBuffer.length)
throw unmarshallingError();
return 0xff & fBuffer[fPos++];
}
@Override
public CoreException unmarshallingError() {
return new CoreException(CCorePlugin.createStatus("Unmarshalling error")); //$NON-NLS-1$
}
public CoreException marshallingError() {
return new CoreException(CCorePlugin.createStatus("Marshalling error")); //$NON-NLS-1$
}
@Override
public void putFixedInt(int value) {
request(4);
fPos += 4;
int p= fPos;
fBuffer[--p]= (byte) (value); value >>= 8;
fBuffer[--p]= (byte) (value); value >>= 8;
fBuffer[--p]= (byte) (value); value >>= 8;
fBuffer[--p]= (byte) (value);
}
@Override
public int getFixedInt() throws CoreException {
if (fPos + 4 > fBuffer.length)
throw unmarshallingError();
int result= 0;
result |= fBuffer[fPos++] & 0xff; result <<= 8;
result |= fBuffer[fPos++] & 0xff; result <<= 8;
result |= fBuffer[fPos++] & 0xff; result <<= 8;
result |= fBuffer[fPos++] & 0xff;
return result;
}
@Override
public void putShort(short value) {
putInt(value);
}
@Override
public void putInt(int value) {
do {
int b = value & 0x7F;
value >>>= 7;
if (value != 0)
b |= 0x80;
putByte((byte) b);
} while (value != 0);
}
@Override
public void putLong(long value) {
do {
int b = (int) value & 0x7F;
value >>>= 7;
if (value != 0)
b |= 0x80;
putByte((byte) b);
} while (value != 0);
}
@Override
public short getShort() throws CoreException {
int result = getInt();
if (result > Short.MAX_VALUE)
unmarshallingError();
return (short) result;
}
@Override
public int getInt() throws CoreException {
int b = getByte();
int value = b & 0x7F;
for (int shift = 7; (b & 0x80) != 0; shift += 7) {
b = getByte();
value |= (b & 0x7F) << shift;
}
return value;
}
@Override
public long getLong() throws CoreException {
int b = getByte();
long value = b & 0x7F;
for (int shift = 7; (b & 0x80) != 0; shift += 7) {
b = getByte();
value |= (b & 0x7F) << shift;
}
return value;
}
private void putRecordPointer(long record) {
request(Database.PTR_SIZE);
Database.putRecPtr(record, fBuffer, fPos);
fPos += Database.PTR_SIZE;
}
private long getRecordPointer() throws CoreException {
final int pos= fPos;
fPos += Database.PTR_SIZE;
if (fPos > fBuffer.length) {
fPos= fBuffer.length;
throw unmarshallingError();
}
return Database.getRecPtr(fBuffer, pos);
}
@Override
public void putCharArray(char[] chars) {
putInt(chars.length);
for (char c : chars) {
putInt(c & 0xFFFF);
}
}
@Override
public char[] getCharArray() throws CoreException {
int len= getInt();
char[] chars= new char[len];
for (int i = 0; i < chars.length; i++) {
chars[i]= (char) getInt();
}
return chars;
}
}