/******************************************************************************* * Copyright (c) 2009, 2010 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 *******************************************************************************/ package org.eclipse.cdt.internal.core.pdom.db; 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.IValue; 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.ProblemType; import org.eclipse.cdt.internal.core.dom.parser.Value; import org.eclipse.cdt.internal.core.pdom.dom.PDOMBinding; import org.eclipse.cdt.internal.core.pdom.dom.PDOMLinkage; import org.eclipse.core.runtime.CoreException; /** * For marshalling types to byte arrays. */ public class TypeMarshalBuffer implements ITypeMarshalBuffer { public final static byte [] EMPTY= {0,0,0,0,0,0}; public final static byte NULL_TYPE= 0; public final static byte INDIRECT_TYPE= (byte) -1; public final static byte BINDING_TYPE= (byte) -2; public final static byte UNSTORABLE_TYPE= (byte) -3; public final static IType UNSTORABLE_TYPE_PROBLEM = new ProblemType(ISemanticProblem.TYPE_NOT_PERSISTED); static { assert EMPTY.length == Database.TYPE_SIZE; } 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 byte[] getBuffer() { return fBuffer; } public void marshalBinding(IBinding binding) throws CoreException { if (binding instanceof ISerializableType) { ((ISerializableType) binding).marshal(this); } else if (binding == null) { putByte(NULL_TYPE); } else { PDOMBinding pb= fLinkage.addTypeBinding(binding); if (pb == null) { putByte(UNSTORABLE_TYPE); } else { putByte(BINDING_TYPE); putByte((byte) 0); putRecordPointer(pb.getRecord()); } } } public IBinding unmarshalBinding() throws CoreException { if (fPos >= fBuffer.length) throw unmarshallingError(); byte firstByte= fBuffer[fPos]; if (firstByte == BINDING_TYPE) { fPos+= 2; long rec= getRecordPointer(); return (IBinding) fLinkage.getNode(rec); } else if (firstByte == NULL_TYPE || firstByte == UNSTORABLE_TYPE) { fPos++; return null; } IType type= fLinkage.unmarshalType(this); if (type == null || type instanceof IBinding) return (IBinding) type; throw unmarshallingError(); } public void marshalType(IType type) throws CoreException { if (type instanceof IBinding) { marshalBinding((IBinding) type); } else if (type instanceof ISerializableType) { ((ISerializableType) type).marshal(this); } else if (type == null) { putByte(NULL_TYPE); } else { assert false : "Cannot serialize " + ASTTypeUtil.getType(type) + "(" + type.getClass().getName() + ")"; //$NON-NLS-1$//$NON-NLS-2$//$NON-NLS-3$ putByte(UNSTORABLE_TYPE); } } public IType unmarshalType() throws CoreException { if (fPos >= fBuffer.length) throw unmarshallingError(); byte firstByte= fBuffer[fPos]; if (firstByte == BINDING_TYPE) { fPos+= 2; long rec= getRecordPointer(); return (IType) fLinkage.getNode(rec); } else if (firstByte == NULL_TYPE) { fPos++; return null; } else if (firstByte == UNSTORABLE_TYPE) { fPos++; return UNSTORABLE_TYPE_PROBLEM; } return fLinkage.unmarshalType(this); } public void marshalValue(IValue value) throws CoreException { if (value instanceof Value) { ((Value) value).marshall(this); } else { putByte(NULL_TYPE); } } public IValue unmarshalValue() throws CoreException { if (fPos >= fBuffer.length) throw unmarshallingError(); return Value.unmarshal(this); } 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; } } } public void putByte(byte b) { request(1); fBuffer[fPos++]= b; } public int getByte() throws CoreException { if (fPos+1 > fBuffer.length) throw unmarshallingError(); return 0xff & fBuffer[fPos++]; } 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$ } public void putShort(short value) { request(2); fBuffer[fPos++]= (byte)(value >> 8); fBuffer[fPos++]= (byte)(value); } public int getShort() throws CoreException { if (fPos+2 > fBuffer.length) throw unmarshallingError(); final int byte1 = 0xff & fBuffer[fPos++]; final int byte2 = 0xff & fBuffer[fPos++]; return (((byte1 << 8) | (byte2 & 0xff))); } public void putInt(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); } public int getInt() 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; } public void putLong(long value) { request(8); fPos += 8; 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); value >>= 8; fBuffer[--p]= (byte)(value); value >>= 8; fBuffer[--p]= (byte)(value); value >>= 8; fBuffer[--p]= (byte)(value); value >>= 8; fBuffer[--p]= (byte)(value); } public long getLong() throws CoreException { if (fPos+8 > fBuffer.length) throw unmarshallingError(); long result= 0; result |= fBuffer[fPos++] & 0xff; result <<= 8; result |= fBuffer[fPos++] & 0xff; result <<= 8; result |= fBuffer[fPos++] & 0xff; result <<= 8; result |= fBuffer[fPos++] & 0xff; result <<= 8; result |= fBuffer[fPos++] & 0xff; result <<= 8; result |= fBuffer[fPos++] & 0xff; result <<= 8; result |= fBuffer[fPos++] & 0xff; result <<= 8; result |= fBuffer[fPos++] & 0xff; return result; } private void putRecordPointer(long record) { request(Database.PTR_SIZE); Chunk.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 Chunk.getRecPtr(fBuffer, pos); } public void putCharArray(char[] chars) { putShort((short) chars.length); for (char c : chars) { putShort((short) c); } } public char[] getCharArray() throws CoreException { int len= getShort(); char[] expr= new char[len]; for (int i = 0; i < expr.length; i++) { expr[i]= (char) getShort(); } return expr; } }