package sharpen.xobotos.api.interop.marshal; import com.thoughtworks.xstream.annotations.XStreamAlias; import com.thoughtworks.xstream.annotations.XStreamAsAttribute; import com.thoughtworks.xstream.annotations.XStreamOmitField; import org.eclipse.jdt.core.dom.ITypeBinding; import sharpen.core.csharp.ast.*; import sharpen.core.framework.BindingUtils; import sharpen.xobotos.api.interop.IManagedReturnContext; import sharpen.xobotos.api.interop.NativeHandle; import sharpen.xobotos.api.interop.Signature.Flags; import sharpen.xobotos.api.interop.Signature.Mode; import sharpen.xobotos.api.interop.glue.AbstractTypeReference; import sharpen.xobotos.api.interop.glue.ConstPointerType; import sharpen.xobotos.api.interop.glue.DereferenceExpression; import sharpen.xobotos.api.interop.glue.Expression; import sharpen.xobotos.api.interop.glue.PointerType; import sharpen.xobotos.config.ConfigurationException; import sharpen.xobotos.config.annotations.AttributeReference; import java.util.Collections; import java.util.List; public class MarshalAsClass extends MarshalInfo { @XStreamAlias(value = "native-class") public static class Entry extends MarshalEntry { @XStreamOmitField @AttributeReference("native-handle") private NativeHandle _nativeHandle; @XStreamAsAttribute @XStreamAlias("flags") private Flags _flags; public NativeHandle getNativeHandle() { return _nativeHandle; } @Override public MarshalInfo resolve(ITypeBinding type) { if ((type != null) && type.isArray()) return null; if (_nativeHandle == null) throw new ConfigurationException( "Missing 'native-handle' in MarshalAsClass"); return new MarshalAsClass(type, _flags, _nativeHandle); } } private final Flags _overrideFlags; private final List<String> _includes; private final String _nativeClass; private final NativeHandle _nativeHandle; public MarshalAsClass(ITypeBinding type, Flags flags, NativeHandle handle) { super(type); this._overrideFlags = flags; this._includes = handle.getIncludes(); this._nativeClass = handle.getNativeClass(); this._nativeHandle = handle; } private boolean isManagedClass() { return (getType() != null) && getType().isClass(); } @Override public boolean isPrimitiveType() { return true; } public String getNativeClass() { return _nativeClass; } public NativeHandle getNativeHandle() { return _nativeHandle; } @Override public List<String> getIncludes() { return _includes != null ? Collections.unmodifiableList(_includes) : null; } @Override public CSTypeReferenceExpression getManagedType(Mode mode, Flags flags) { if (flags == Flags.ELEMENT) return new CSTypeReference("System.IntPtr"); else if (isManagedClass()) return new CSTypeReference(BindingUtils.qualifiedName(getType())); else if (_nativeHandle != null) return _nativeHandle.getManagedType(); else return new CSTypeReference("System.IntPtr"); } @Override public CSTypeReferenceExpression getPInvokeType(Mode mode, Flags flags) { if (flags == Flags.ELEMENT) return new CSTypeReference("System.IntPtr"); else return _nativeHandle.getManagedType(); } @Override public AbstractTypeReference getNativeType(Mode mode, Flags flags) { if ((flags != Flags.ELEMENT) && (mode == Mode.IN)) return new ConstPointerType(_nativeClass); else return new PointerType(_nativeClass); } @Override public CSExpression marshalIn(CSExpression expr, Mode mode, Flags flags) { if (flags == Flags.ELEMENT) { CSExpression infix = new CSInfixExpression("!=", expr, new CSNullLiteralExpression()); CSExpression instance; if (isManagedClass()) instance = new CSMemberReferenceExpression(expr, _nativeHandle.getField()); else instance = expr; CSExpression handleRef = new CSMemberReferenceExpression(instance, "Handle"); CSExpression zeroRef = new CSReferenceExpression("System.IntPtr.Zero"); return new CSConditionalExpression(infix, handleRef, zeroRef); } if (isManagedClass()) { CSExpression infix = new CSInfixExpression("!=", expr, new CSNullLiteralExpression()); String handle = _nativeHandle.getField(); CSExpression handleRef = new CSMemberReferenceExpression(expr, handle); CSExpression zeroRef = new CSMemberReferenceExpression(_nativeHandle.getManagedType(), "Zero"); return new CSConditionalExpression(infix, handleRef, zeroRef); } if ((flags == Flags.ALLOW_NULL) || (_overrideFlags == Flags.ALLOW_NULL)) { CSExpression infix = new CSInfixExpression("!=", expr, new CSNullLiteralExpression()); CSExpression zeroRef = new CSMemberReferenceExpression(_nativeHandle.getManagedType(), "Zero"); return new CSConditionalExpression(infix, expr, zeroRef); } else { return expr; } } @Override public CSExpression marshalRetval(IManagedReturnContext context, CSExpression expr) { if (isManagedClass()) { CSConstructorInvocationExpression cie = new CSConstructorInvocationExpression(getManagedType( Mode.OUT, null)); cie.addArgument(expr); return cie; } return expr; } @Override public Expression marshalNativeArg(Expression expr, Mode mode, Flags flags) { if ((flags == Flags.ALLOW_NULL) || (_overrideFlags == Flags.ALLOW_NULL) || (flags == Flags.ELEMENT)) return expr; if ((mode == null) || (mode == Mode.IN) || (mode == Mode.INSTANCE)) return new DereferenceExpression(expr); return expr; } }